本电子钟已经全部测试OK,带闹钟功能,年月日时分秒星期温度,四个按键可设置闹钟调节时间,温度可以显示正125度到负的55度之间,时间走时的话,我测试了一个月,误差不到1分钟。本人已经录制成视频,视频里面有详细的介绍,感兴趣的可以看看 。视频及多图还有源代码的地址:http://www.51hei.com/bbs/dpj-26057-1.html
程序:
#include#include #define uchar unsigned char#define uint unsigned intsbit rs=P1^0;//寄存器选择sbit rw=P1^1;//读写信号线sbit lcden=P1^2;//led使能端sbit scl=P1^3;//时钟线sbit rst=P1^5;//复位线sbit io=P1^4;//数据口sbit key_set_time=P3^4;//设置时间键sbit key_add=P3^5;//加键sbit key_minus=P3^6;//减键sbit key_set_alarm=P3^7;//设置闹钟键sbit bee=P1^6;//蜂鸣器接口sbit dq=P1^7;//ds18b20测温uchar getTimebuf[7];//存放时间数据uchar time[]={" : : "};//时间格式字符串uchar date[]={"20 - - "};//日期格式字符串uchar weeklist[]={"SunMonTueWedThuFriSat"};//星期字符列表uchar week[]={" "};//星期格式字符串int count;//设定秒分时日月星期年的时候count的值分别为1235647int alarm;//是否进入闹钟设置界面 123分别代表开关 分 小时的设置int isOpen;//闹钟是否开启 默认不开启int fen,shi;//闹钟的分钟小时int isRing;//闹钟是否在响uchar isInit_1302;//是否初始化时钟完毕int num;int temperature;//温度int temp_flag;//温度正负标志void delay(uint x){ int y; while(x--){ for(y=100;y>0;y--); }}void write_1602com(uchar com){ //1602写指令 rs=0; lcden=0; P2=com; delay(5); lcden=1; delay(5); lcden=0;}void write_1602data(uchar dat){ //1602写数据 rs=1; lcden=0; P2=dat; delay(5); lcden=1; delay(5); lcden=0;}void init_1602(){ //初始化1602液晶 rw=0; lcden=0; write_1602com(0x38);//设置显示模式 write_1602com(0x0c);//显示开关及光标是否显示和闪动 write_1602com(0x06);//光标移动方向 write_1602com(0x01);//清屏}void write_ds1302_byte(uchar temp){ //ds1302写一个字节数据 uchar i; for(i=0;i<8;i++){ io=temp&0x01;//将数据放到IO口上 scl=0;//scl为低时准备数据 scl=1;//上升沿写入 temp>>=1; }}void write_ds1302(uchar add,uchar dat){ //向地址add写入数据dat rst=0; scl=0; rst=1; write_ds1302_byte(add); write_ds1302_byte(dat); scl=1; rst=0;}uchar read_ds1302(uchar add){ //ds1302读数据 uchar i,dat; rst=0; scl=0; rst=1; write_ds1302_byte(add);//首先写入要读的数据处的地址 for(i=0;i<8;i++){ if(io==1){ dat|=0x80; } scl=1; scl=0;//下降沿读取数据 dat>>=1; } scl=1; rst=0; return dat;}void read_time(uchar curr_time[]){ uchar i; uchar ucAddr = 0x81; for (i=0;i<7;i++){ curr_time[i] = read_ds1302(ucAddr);//格式为: 秒 分 时 日 月 星期 年 ucAddr += 2; }}void set_time(uchar *pSecDa){ //设定时间 uchar i; uchar ucAddr = 0x80; write_ds1302(0x8e,0x00); for(i =7;i>0;i--){ write_ds1302(ucAddr,*pSecDa); //秒 分 时 日 月 星期 年 pSecDa++; ucAddr+=2; } write_ds1302(0x8e,0x80);}void init_ds1302(){ //ds1302初始化 isInit_1302=read_ds1302(0x81);//读出时钟状态 if(isInit_1302&0x80){//说明没有初始化 write_ds1302(0x8e,0x00);//关闭写保护 以后一直开着 write_ds1302(0x90,0xa5); //辅助电源充电命令 一个二极管 一个2K电阻 write_ds1302(0x80,0x00);//秒 CH置0 开启时钟 write_ds1302(0x82,0x59);//分 write_ds1302(0x84,0x10);//时 write_ds1302(0x86,0x07);//日 write_ds1302(0x88,0x05);//月 write_ds1302(0x8a,0x04);//星期 write_ds1302(0x8c,0x14);//年 write_ds1302(0x8e,0x80); }}char int_to_char(int temp){ //把0到9对应的数字转为字符 char x='0'; switch(temp){ case 0:x='0';break; case 1:x='1';break; case 2:x='2';break; case 3:x='3';break; case 4:x='4';break; case 5:x='5';break; case 6:x='6';break; case 7:x='7';break; case 8:x='8';break; case 9:x='9';break; } return x;}int ds18b20_read_temp();void display(){ uchar bai,shi,ge,point,fuhao; read_time(getTimebuf);//时时读取时间 time[6]=(getTimebuf[0])/16+48;//格式化时间秒 time[7]=(getTimebuf[0])%16+48; time[3]=(getTimebuf[1])/16+48;//格式化时间分 time[4]=(getTimebuf[1])%16+48; time[0]=(getTimebuf[2])/16+48;//格式化时间小时 time[1]=(getTimebuf[2])%16+48; date[8]=getTimebuf[3]/16+48;//格式化日期日 date[9]=getTimebuf[3]%16+48; date[5]=getTimebuf[4]/16+48;//格式化日期月 date[6]=getTimebuf[4]%16+48; date[2]=getTimebuf[6]/16+48;//格式化日期年 date[3]=getTimebuf[6]%16+48; week[0]=weeklist[(getTimebuf[5]%10)*3];//格式化星期 week[1]=weeklist[(getTimebuf[5]%10)*3+1]; week[2]=weeklist[(getTimebuf[5]%10)*3+2]; write_1602com(0x80+1); for(num=0;num<10;num++){ write_1602data(date[num]); } write_1602data(' '); for(num=0;num<3;num++){ write_1602data(week[num]); } write_1602com(0x80+0x40); for(num=0;num<8;num++){ write_1602data(time[num]); } //显示温度值 write_1602com(0x80+0x40+8);//设置数据指针 temperature=ds18b20_read_temp(); bai=temperature/1000+0x30; shi=temperature%1000/100+0x30; ge=temperature%100/10+0x30; point=temperature%100%10+0x30; if(temp_flag==1){//说明为正数 不显示符号位 125.6 25.7两种 fuhao=0x20;//显示空白 if(bai==0x30){ bai=0x20;//如果百位为0 不显示 if(shi==0x30){ shi=0x20;//如果百位为0 十位也为0 都不显示 } } write_1602data(fuhao); write_1602data(bai); write_1602data(shi); }else{ fuhao=0x2d;//显示负号 -2.5 -25.8两种 write_1602data(0x20);//因为负数最低到55,所以不显示百位 if(shi==0x30){ write_1602data(0x20); write_1602data(fuhao); }else{ write_1602data(fuhao); write_1602data(shi); } } write_1602data(ge); write_1602data('.'); write_1602data(point); write_1602data(0xdf); write_1602data('C');}void display_alarm(uchar add,int dat){ //把设定的时分显示出来 int x,y; x=dat/10; y=dat%10; write_1602com(add); write_1602data(int_to_char(x)); write_1602com(add+1);//防止写后地址自动向后加一 光标闪烁看不到 write_1602data(int_to_char(y)); write_1602com(add+1);}void init_alarm(){ //闹钟设置界面 只有首次进入才执行 uchar code x[]="SET ALARM"; uchar i; if(alarm==0){ write_1602com(0x01);//清屏 write_1602com(0x80+3);//设置数据指针 for(i=0;i<9;i++){ write_1602data(x[i]); } display_alarm(0x80+0x40+5,shi);//载入闹钟的时分 write_1602com(0x80+0x40+7); write_1602data(':'); display_alarm(0x80+0x40+8,fen); if(isOpen){//初始化的时候如果已经设定闹钟则显示ON write_1602com(0x80+0x40+13); write_1602data(' '); write_1602data('O'); write_1602data('N'); }else{ write_1602com(0x80+0x40+13); write_1602data('O'); write_1602data('F'); write_1602data('F'); } }}void key_scan(){ int i; uchar code tips1[]="SET SUCCESS";//闹钟设置成功的提示 uchar code tips2[]="CANCEL SUCCESS";//取消闹钟的提示 if(key_set_time==0){//检测是否按下 delay(10);//消抖 if(key_set_time==0){//再次检测是否按下 while(!key_set_time);//检测是否松开 delay(10);//延时消抖 while(!key_set_time);//再次检测是否松开 if(alarm==0){//当没有显示闹钟界面时才显示时间设定 count++; write_ds1302(0x80,0x80);//让时钟停止 if(count==8){ //继续走时,说明时间已经设定好了 write_1602com(0x0c);//让光标消失 write_ds1302(0x80,0);//让时钟继续 set_time(getTimebuf);//写入新的时间 count=0; return; } switch(count){ case 1: write_1602com(0x80+0x40+7);//在秒的位置 break; case 2: write_1602com(0x80+0x40+4);//在分的位置 break; case 3: write_1602com(0x80+0x40+1);//在时的位置 break; case 4: write_1602com(0x80+14);//在星期的位置 break; case 5: write_1602com(0x80+10);//在日的位置 break; case 6: write_1602com(0x80+7);//在月的位置 break; case 7: write_1602com(0x80+4);//在年的位置 break; } write_1602com(0x0f);//让光标闪烁 } } } if(key_add==0){//检测是否按下 delay(10);//消抖 if(key_add==0){//再次检测是否按下 while(!key_add);//检测是否松开 delay(10);//延时消抖 while(!key_add);//再次检测是否松开 if(count!=0){ switch(count){ case 1: //在秒的位置 getTimebuf[0]++; if(getTimebuf[0]==0x5a){ getTimebuf[0]=0; } if(getTimebuf[0]==0x4a){ getTimebuf[0]=0x50; } if(getTimebuf[0]==0x3a){ getTimebuf[0]=0x40; } if(getTimebuf[0]==0x2a){ getTimebuf[0]=0x30; } if(getTimebuf[0]==0x1a){ getTimebuf[0]=0x20; } if(getTimebuf[0]==0x0a){ getTimebuf[0]=0x10; } time[6]=(getTimebuf[0])/16+48;//格式化时间秒 time[7]=(getTimebuf[0])%16+48; write_1602com(0x80+0x40+6);//在秒的位置 write_1602data(time[6]); write_1602com(0x80+0x40+7);//在秒的位置 write_1602data(time[7]); write_1602com(0x80+0x40+7);//让光标在秒的位置闪烁 break; case 2: //在分的位置 getTimebuf[1]++; if(getTimebuf[1]==0x5a){ getTimebuf[1]=0; } if(getTimebuf[1]==0x4a){ get