本程序完全测试通过 按上面的电路图 用1602液晶显示 可调时间.#include<reg52.h> #define uint unsigned int #define uchar unsigned char #define w_Sec 0x80 #define w_Min 0x82 #define w_Hou 0x84 #define w_Day 0x86 #define w_Mou 0x88 #define w_xi 0x8a #define w_Yea 0x8c // DS1302写数据 #define r_Sec 0x81 #define r_Min 0x83 #define r_Hou 0x85 #define r_Day 0x87 #define r_Mou 0x89 #define r_xi 0x8b #define r_Yea 0x8d //DS1302读数据 #define w_protect 0x8e //DS1302写保护 uchar code table[]="11-6-20"; //制作时间 uchar code time1[]="00:00:00"; //时间模式1,用于普通计时 uchar code time2[]="00:00:00:00"; //时间模式2,用于秒表计时 uchar code time3[]="00:00"; //时间模式3,用于闹钟设置 uchar code miaobiao[]="StopWatch"; uchar code naozhong[]="Alarm"; uchar code stuinfo1[]="ZLW0800730203"; uchar code stuinfo2[]="LWL0807030209"; uchar code xi1[]="Mon"; uchar code xi2[]="Tue"; uchar code xi3[]="Wed"; uchar code xi4[]="Thu"; uchar code xi5[]="Fri"; uchar code xi6[]="Sat"; uchar code xi7[]="Sun"; unsigned char code str1[]={"Temperature:"}; unsigned char code str2[]={" "}; uchar data disdata[5]; uint tvalue; //温度值 uchar tflag; //温度正负标志 //18B20 sbit RS=P2^0; sbit RW=P2^1; sbit EN=P2^2; //1602控制端定义 sbit ACC_7 = ACC^7; //位寻址寄存器 sbit SCK = P1^1; //DS1302时钟信号 sbit SDA = P1^0; //DS1302数据信号 sbit RST = P1^2 ; //DS1302片选信号 sbit k1=P1^4; sbit k2=P1^5; sbit k3=P1^6; sbit k4=P1^7; sbit alarm=P3^7; sbit DQ = P2^7; //DS18B20 uint i,shi,fen,miao,haomiao,nian,yue,ri,num,x,menu,n,nshi=0,nfen=1; //nshi、nfen用来判别闹钟,与系统时间对比 uchar sshi,sfen,smiao,snian,syue,sri,sxi; /***********************延时程序*********************************/ void delay(uint z) { uint x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); } /********************************ds1302***************************************/ //***************向DS1302写入一字节数据 void Write1302(uchar addr, uchar d) { unsigned char i; SCK=0; RST=1; //写入目标地址:addr for (i = 0; i < 8; i ++) { if (addr & 0x01) { SDA=1; } else { SDA=0; } //并口转串口 SCK=1; //上升沿写数据 SCK=0; addr = addr >> 1; } //写入数据:d for (i = 0; i < 8; i ++) { if (d & 0x01) { SDA=1; } else { SDA=0; } SCK=1; SCK=0; d = d >> 1; } RST=0; //停止DS1302总线 } //*************************从DS1302读出一字节数据 unsigned char Read1302(uchar addr) { unsigned char i; unsigned char temp; unsigned char dat1=0; unsigned char dat2=0; SCK=0; RST=1; //写入目标地址:addr for (i = 0; i < 8; i ++) { if (addr & 0x01) { SDA=1; } else { SDA=0; } SCK=1; SCK=0; addr = addr >> 1; } //输出数据:temp for (i = 0; i < 8; i ++) { temp = temp >> 1; if (SDA) { temp |= 0x80; } else { temp &= 0x7F; } SCK=1; SCK=0; } RST=0; //停止DS1302总线 dat2 = temp/16; // 数据进制转换 dat1 = temp%16; dat1 = dat2*10+dat1; return dat1; } /*****************************1602显示******************************************/ void write_add(uchar add) //1602控制字 { RS=0; P0=add; EN=1; delay(5); EN=0; } void write_date(uchar date) //1602显示字 { RS=1; P0=date; EN=1; delay(5); EN=0; } void writesfm(uchar add,uchar date) //1602显示时分秒 { uchar s,g; s = date/10; g = date%10; write_add(0x80+0x40+add); write_date(0x30+s); write_date(0x30+g); } void writenyr(uchar add,uchar date) //1602显示年月日 { uchar s,g; s=date/10; g=date%10; write_add(0x80+0x00+add); write_date(0x30+s); write_date(0x30+g); } void writexi(uchar a) { write_add(0x80+0x00+11); if(a==1) { for(i=0;i<3;i++) { write_date(xi1[i]); delay(5); } } if(a==2) { for(i=0;i<3;i++) { write_date(xi2[i]); delay(5); } } if(a==3) { for(i=0;i<3;i++) { write_date(xi3[i]); delay(5); } } if(a==4) { for(i=0;i<3;i++) { write_date(xi4[i]); delay(5); } } if(a==5) { for(i=0;i<3;i++) { write_date(xi5[i]); delay(5); } } if(a==6) { for(i=0;i<3;i++) { write_date(xi6[i]); delay(5); } } if(a==7) { for(i=0;i<3;i++) { write_date(xi7[i]); delay(5); } } } void writefuhao(void) //写符号 { write_add(0x80+0x00+2); write_date(table[2]); delay(10); write_add(0x80+0x00+5); write_date(table[2]); delay(10); write_add(0x80+0x40+2); write_date(time1[2]); delay(10); write_add(0x80+0x40+5); write_date(time1[2]); delay(10); } /******************************ds1820程序***************************************/ void delay_18B20(unsigned int i)//延时1微秒 { while(i--); } void ds1820rst() //ds1820复位 { unsigned char x=0; DQ = 1; //DQ复位 delay_18B20(4); //延时 DQ = 0; //DQ拉低 delay_18B20(100); //精确延时大于480us DQ = 1; //拉高 delay_18B20(40); } uchar ds1820rd() //读数据 { unsigned char i=0; unsigned char dat = 0; for (i=8;i>0;i--) { DQ = 0; //给脉冲信号 dat>>=1; DQ = 1; //给脉冲信号 if(DQ) dat|=0x80; delay_18B20(10); } return(dat); } void ds1820wr(uchar wdata) //写数据 { unsigned char i=0; for (i=8; i>0; i--) { DQ = 0; DQ = wdata&0x01; delay_18B20(10); DQ = 1; wdata>>=1; } } read_temp() //读取温度值并转换 { uchar a,b; ds1820rst(); ds1820wr(0xcc); //跳过读序列号 ds1820wr(0x44); //启动温度转换 ds1820rst(); ds1820wr(0xcc); //跳过读序列号 ds1820wr(0xbe);//读取温度 a=ds1820rd(); b=ds1820rd(); tvalue=b; tvalue<<=8; tvalue=tvalue|a; if(tvalue<0x0fff) tflag=0; else { tvalue=~tvalue+1; tflag=1; } tvalue=tvalue*(0.625);//温度值扩大10倍,精确到1位小数 return(tvalue); } /*******************************************************************/ void ds1820disp() //温度值显示 { uchar flagdat; disdata[0]=tvalue/1000+0x30; //百位数 disdata[1]=tvalue%1000/100+0x30; //十位数 disdata[2]=tvalue%100/10+0x30; //个位数 disdata[3]=tvalue%10+0x30; //小数位 if(tflag==0) flagdat=0x20; //正温度不显示符号 else flagdat=0x2d; //负温度显示负号:- if(disdata[0]==0x30) { disdata[0]=0x20; //如果百位为0,不显示 if(disdata[1]==0x30) { disdata[1]=0x20; //如果百位为0,十位为0也不显示 } } write_add(0x80+0x40+8); write_date(flagdat); //显示符号位 write_add(0x80+0x40+9); write_date(disdata[0]); //显示百位 write_add(0x80+0x40+10); write_date(disdata[1]); //显示十位 write_add(0x80+0x40+11); write_date(disdata[2]); //显示个位 write_add(0x80+0x40+12); write_date(0x2e); //显示小数点 write_add(0x80+0x40+13); write_date(disdata[3]); //显示小数位 write_add(0x80+0x40+14); write_date(0xdf); //显示"。" write_add(0x80+0x40+15); write_date(0x63); //显示"c" } void init_info(void) { write_add(0x80+0x00+0); for(i=0;i<14;i++) { write_date(stuinfo1[i]); delay(5); } write_add(0x80+0x40+0); for(i=0;i<14;i++) { write_date(stuinfo2[i]); delay(5); } } void Speak1() //闹铃 { alarm = 0; smiao = Read1302(r_Sec); sfen = Read1302(r_Min); sshi = Read1302(r_Hou); snian = Read1302(r_Yea); syue = Read1302(r_Mou); sri = Read1302(r_Day); sxi = Read1302(r_xi); writefuhao(); writesfm(0,sshi); writesfm(3,sfen); writesfm(6,smiao); writenyr(0,snian); writenyr(3,syue); writenyr(6,sri); writexi(sxi); delay(500); alarm = 1; delay(500); } void Speak2() { alarm=0; delay(2000); alarm=1; } void Normal() //正常显示时间功能 { smiao = Read1302(r_Sec); sfen = Read1302(r_Min); sshi = Read1302(r_Hou); snian = Read1302(r_Yea); syue = Read1302(r_Mou); sri = Read1302(r_Day); sxi = Read1302(r_xi); //读取时间数据 if((nshi==sshi)&&(nfen==sfen)) //闹钟铃响 { for(i=0;i<10;i++) { Speak1(); } while((k1==1)||(k2==1)||(k3==1)||(k4==1)) //按下任意键,闹钟停止闹铃 { alarm=1; } } //关闭蜂鸣器 if((sshi==0||sshi==1||sshi==2||sshi==3||sshi==4||sshi==5||sshi==6||sshi==7 ||sshi==8||sshi==9||sshi==10||sshi==11||sshi==12||sshi==13||sshi==14||sshi==15||sshi==16 ||sshi==1||sshi==18||sshi==19||sshi==20||sshi==21||sshi==22||sshi==23)&&(sfen==0)&&(smiao==0)) { Speak2(); //整点报时 } alarm=1; //关闭蜂鸣器 writefuhao(); writesfm(0,sshi); writesfm(3,sfen); writesfm(6,smiao); writenyr(0,snian); writenyr(3,syue); writenyr(6,sri); writexi(sxi); } void StopWatch () reentrant //秒表功能 { haomiao=0; miao=0; fen=0; shi=0; write_add(0x01); //清屏 write_add(0x0c); write_add(0x80+0x00+0); for(i=0;i<9;i++) { write_date(miaobiao[i]); delay(5); } write_add(0x80+0x40+0); for(i=0;i<11;i++) { write_date(time2[i]); delay(5); } while(!k4); while(k4!=0) { if(k1==0) { delay(10); //消抖 if(k1==0) StopWatch(); } haomiao++; if(haomiao==100) { haomiao=0; miao++; if(miao==60) { miao=0; fen++; if(fen==60) { fen=0; shi++; if(shi==24) { shi=0; } writesfm(0,shi); } writesfm(3,fen); } writesfm(6,miao); } writesfm(9,haomiao); } /*TR0 = 0; menu=3;*/ } void key() //闹钟时的按键功能 { if(k1==0) { delay(10); if(k1==0) { n++; while(!k1); if(n==1) { write_add(0x0f); write_add(0x80+0x40+4); //写shi } if(n==2) { write_add(0x0f); write_add(0x80+0x40+7); //写fen } if(n==3) { n=0; nfen=fen; nshi=shi; //确认 write_add(0x0c); //光标不闪烁 } } } if(k2==0) { delay(10); if(k2==0) { while(!k2); if(n==1) { shi++; if(shi==24) shi=0; writesfm(4,shi); } if(n==2) { fen++; if(fen==60) fen=0; writesfm(7,fen); } } } if(k3==0) { delay(10); if(k3==0) { while(!k3); if(n==1) { shi--; if(shi==-1) shi=23; writesfm(4,shi); } if(n==2) { fen--; if(fen==-1) fen=59; writesfm(7,fen); } } } menu=4; } void Alarm(void) //设定闹钟功能,k4键跳转其他功能 { write_add(0x06); write_add(0x01); //清屏 write_add(0x80+0x00+0); for(i=0;i<5;i++) { write_date(naozhong[i]); //显示Alarm标识符 } write_add(0x80+0x40+4); writesfm(4,nshi); write_date(0x3a); writesfm(7,nfen); shi=nshi; fen=nfen; while(!k4); while(k4) { key(); } write_add(0x0c); //开显示,不显示光标 } void key1(void) { if(k1==0) //设置光标所在位置 { delay(10); //去抖 if(k1==0) { num++; while(!k1); if(num==1) { write_add(0x0f); //显示光标并闪烁 write_add(0x80+0x40+6); } if(num==2) { write_add(0x0f); //显示光标并闪烁 write_add(0x80+0x40+3); } if(num==3) { write_add(0x0f); //显示光标并闪烁 write_add(0x80+0x40+0); } if(num==4) { write_add(0x0f); //显示光标并闪烁 write_add(0x80+0x00+6); } if(num==5) { write_add(0x0f); //显示光标并闪烁 write_add(0x80+0x00+3); } if(num==6) { write_add(0x0f); //显示光标并闪烁 write_add(0x80+0x00+0); } if(num==7) { write_add(0x0f); //显示光标并闪烁 write_add(0x80+0x00+11); } if(num==8) { num=0; write_add(0x0c); } } } } void key2(void) { Write1302(w_protect,0x00); //禁止写保护 if(k2==0) //实现加法 { delay(10); if(k2==0) { while(!k2); if(num==1) { miao++; if(miao==60) { miao=0; } writesfm(6,miao); Write1302(w_Sec,(miao/10)*16+miao%10); //将miao转换成BCD码 } if(num==2) { fen++; if(fen==60) { fen=0; } writesfm(3,fen); Write1302(w_Min,(fen/10)*16+fen%10); } if(num==3) { shi++; if(shi==24) { shi=0; } writesfm(0,shi); Write1302(w_Hou,(shi/10)*16+shi%10); } if(num==4) { ri++; if(ri==30) { ri=0; } writenyr(6,ri); Write1302(w_Day,(ri/10)*16+ri%10); } if(num==5) { yue++; if(yue==13) { yue=1; } writenyr(3,yue); Write1302(w_Mou,(yue/10)*16+yue%10); } if(num==6) { nian++; if(nian==100) { nian=0; } writenyr(0,nian); Write1302(w_Yea,(nian/10)*16+nian%10); } if(num==7) { x++; writexi(x); Write1302(w_xi,(x/10)*16+x%10); if(x==7) { x=0; } } } } } void key3(void) { Write1302(w_protect,0x00); //禁止写保护 if(k3==0) //实现减法 { delay(10); if(k3==0) { while(!k3); if(num==1) { miao--; if(miao==-1) { miao=59; } writesfm(6,miao); Write1302(w_Sec,(miao/10)*16+miao%10); } if(num==2) { fen--; if(fen==-1) { fen=59; } writesfm(3,fen); Write1302(w_Min,(fen/10)*16+fen%10); } if(num==3) { shi--; if(shi==-1) { shi=23; } writesfm(0,shi); Write1302(w_Hou,(shi/10)*16+shi%10); } if(num==4) { ri--; if(ri==-1) { ri=30; } writenyr(6,ri); Write1302(w_Day,(ri/10)*16+ri%10); } if(num==5) { yue--; if(yue==-1) { yue=12; } writenyr(3,yue); Write1302(w_Mou,yue); } if(num==6) { nian--; if(nian==-1) { nian=99; } writenyr(0,nian); Write1302(w_Yea,(yue/10)*16+yue%10); } if(num==7) { x--; writexi(x); Write1302(w_xi,(x/10)*16+x%10); if(x==1) { x=8; } } } } } void key4() { if(k4==0) { delay(10); if(k4==0) { while(!k4); menu++; } } } void TimeSet() { write_add(0x0f); write_add(0x80+0x40+9); while(k4) { key1(); key2(); key3(); } Write1302(w_protect,0x00); //写保护 menu=2; } void init_DS1302(void) { Write1302(w_protect,0x00); //禁止写保护 Write1302(w_Sec,0x56); Write1302(w_Min,0x59); Write1302(w_Hou,0x23); //24小时模式 Write1302(w_xi,0x03); Write1302(w_Day,0x28); Write1302(w_Mou,0x02); Write1302(w_Yea,0x11); //初始化系统时间 2011年5月11日周三12:12:12 Write1302(w_protect,0x80); //写保护 } void disp(void) { key4(); if(menu==0) { Normal(); read_temp(); //读取温度 ds1820disp();//显示 } if(menu==1) { TimeSet(); } num=0; if(menu==2) { StopWatch(); } if(menu==3) { Alarm(); } if(menu==4) { init_info(); } if(menu==5) { menu=0; write_add(0x01); //清屏 } } void main() { init_DS1302(); //初始化1302 EN=1; RW=0; //写命令 write_add(0x38); //设置16*2行显示,5*7点阵,8位数据接口 write_add(0x0c); //开显示,不显示光标 write_add(0x06); write_add(0x01); //清屏 while(1) { disp(); //显示 } }