新闻中心

EEPW首页>嵌入式系统>设计应用> 基于DS1302的简易数码管电子钟

基于DS1302的简易数码管电子钟

作者: 时间:2012-08-10 来源:网络 收藏
#includereg51.h>#includeintrins.h>#include".h"#include"KEY.h"#include"IIC.H"#define uchar unsigned char#define uint unsigned int#define LEDIO P0#define LEDCHIP P2sbit BEEP=P3^7;/*************************定义**************************************///段码 0 1 2 3 4 5 6 7 8 9 A B - P duchar code led[15]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x40,0x73,0x5E};//位选信号 全灭uchar code selchip[7]={0x01,0x02,0x04,0x08,0x10,0x20,0x10};//数据格式: 秒 分 时 日 月 星期 年uchar time_temp[7]={0x00,0x50,0x10,0x12,0x30,0x01,0x11}; //存放初始化时间及设置ds1302的数据uchar DataTime[7]; //读取的数据/**********************************************************/ uchar display[4][6]={0x06,0x5b,0x6d,0x6f,0x6d,0x6f}; //显示uchar i=0,key1,key2=20,pos=0,p,k; //按键和扫描变量uchar mod=0; //模式:设置时间进入按钮bit bflash=0,clockdown=0; //设置和闹铃标志uchar hour,minute,second,year,month,date; //有关时间的变量寄存uchar ss=1;//闹铃响的次数可以自己修改uchar clock1[3]={0x06,0,0x01},clock2[3]={14,0,0x01}; //闹钟时间与开关,默认开关开uint num=5000; //设置自动返回主界面时间/////////////////////////////////void TimeInit() //定时扫描初始化{EA = 0;TMOD |= 0x10;TH1 = 0xfd;TL1 = 0xe6;EA=1;// ET0=1;ET1=1;TR1=1;}////////////////////////////////////////////////////////*void t0int() interrupt 1 //T0中断程序,控制发音的音调{TR0 = 0; //先关闭T0BEEP = ~BEEP; //输出方波, 发音TH0 = t0h; //下次的中断时间, 这个时间, 控制音调高低TL0 = t0l;TR0 = 1; //启动T0LEDIO=display[mod][i];LEDCHIP=selchip[i];if(i>=5)i=0;elsei++;}*//////////////////////////////////////////void TimeInt() interrupt 3 //定时扫描中断{if(i==pos){if(bflash==1) //闪烁标志;设置时间日期和闹铃{if(k++40){if(i==4)i=0;elsei=i+2;} else{if(p++>40){p=0;k=0;}}}}LEDIO=display[mod][i];LEDCHIP=selchip[i];if(num==0) //自动还回时间界面{mod=0;bflash=0;}elsenum--; if(i>=5)i=0;elsei++;TH1=0xfa;TL1=0xd8;}////////////////////////////////////////////////////////void TimeToBin() //把时间变成2进制{second=DataTime[0]/16*10+DataTime[0]%16;minute=DataTime[1]/16*10+DataTime[1]%16;hour=DataTime[2]/16*10+DataTime[2]%16;date=DataTime[3]/16*10+DataTime[3]%16;month=DataTime[4]/16*10+DataTime[4]%16;year=DataTime[6]/16*10+DataTime[6]%16;}////////////////////////////////////////////////////////void TimeToBCD() //把时间变为BCD码{time_temp[0]=second/10*16+second%10;time_temp[1]=minute/10*16+minute%10;time_temp[2]=hour/10*16+hour%10;time_temp[3]=date/10*16+date%10;time_temp[4]=month/10*16+month%10;time_temp[6]=year/10*16+year%10;}////////////////////////////////////////////////void TimerDis(){ /************************时间扫描设置************************/display[0][0]=led[hour/10];display[0][1]=led[hour%10]|0x80;display[0][2]=led[minute/10];display[0][3]=led[minute%10]|0x80;display[0][4]=led[second/10];display[0][5]=led[second%10];/************************日期扫描设置************************/display[1][0]=led[year/10];display[1][1]=led[year%10]|0x80;display[1][2]=led[month/10];display[1][3]=led[month%10]|0x80;display[1][4]=led[date/10];display[1][5]=led[date%10];/**********************闹铃1扫描设置****************************/display[2][0]=led[10]; //第一个闹钟display[2][1]=led[14-clock1[2]]; //P闹钟开d闹钟关display[2][2]=led[clock1[0]/10];display[2][3]=led[clock1[0]%10]|0x80;display[2][4]=led[clock1[1]/10];display[2][5]=led[clock1[1]%10];/***********************闹铃2扫描设置**************************/display[3][0]=led[11]; //第一个闹钟display[3][1]=led[14-clock2[2]]; //P闹钟开d闹钟关display[3][2]=led[clock2[0]/10];display[3][3]=led[clock2[0]%10]|0x80;display[3][4]=led[clock2[1]/10];display[3][5]=led[clock2[1]%10];/********************************************************///second=DataTime[0]/16*10+DataTime[0]%16;}///////////////////////////////////////////////////////void KeySet(){key1=KeyTab[KeyRvs()]; //读取键盘值if(key2!=key1) //防止连续跳动,释放按键{if(key1=='*'){pos=0; //返回首位方便设置if(!bflash) //先进设置时间的界面mod=0;elsemod=(mod+1)%4; //功能选择bflash=1; //进入时钟设置标志num=5000; //若是没有操作自动返回主界面}/////////////////////////////移位按键选择设置的位置if((key1=='0')(bflash)){pos=(pos+2)%6;num=5000;}if((!bflash)(key1=='0')) //一键关闭闹铃睡懒觉按键,下次又开闹铃{ clockdown=1; }///////////////////////////// 时分秒设置,加按键,if((key1=='#')(bflash)){ num=5000; //if(mod==0) //时间设置{if(pos==0){hour=(hour+1)%24;}else if(pos==2){minute=(minute+1)%60;}else{second=(second+1)%60;}}////////////////////////////////年月日设置if(mod==1){if(pos==0){year=(year+1)%100;}else if(pos==2){month=(month+1)%13;}else{if(month==2) //二月处理{if(year%4==0) //闰年二月date=(date+1)%30;elsedate=(date+1)%29;}/////////////////////////////////////////////////大月设置else if((month==1)||(month==3)||(month==5)||(month==7)||(month==8)||(month==10)||(month==12))date=(date+1)%32;else /////////////////////////////////////////小月设置date=(date+1)%31;} }//////////////////////////////////////////////闹铃1设置if(mod==2){if(pos==0) //闹铃1开关设置{clock1[2]=(clock1[2]+1)%2;}if(pos==2){clock1[0]=(clock1[0]+1)%24;}if(pos==4){clock1[1]=(clock1[1]+1)%60;}}//////////////////////////////////////////////闹铃2设置if(mod==3){if(pos==0) //闹铃2开关设置{clock2[2]=(clock2[2]+1)%2;}if(pos==2){clock2[0]=(clock2[0]+1)%24;}if(pos==4){clock2[1]=(clock2[1]+1)%60;}}}if((!bflash)(key1=='#')) //查看闹铃设置{ mod=(mod+1)%2+2; }///////////////////////////////////////////////确认键设置if(key1=='D'){if(bflash) //清除设置标志{bflash=0;mod=0;TimeToBCD();Set_Ds1302(time_temp);while(!Write_Nbyte_iic(SLAVE,0x50,clock1,3));while(!Write_Nbyte_iic(SLAVE,0x60,clock2,3));}else //切换时间和日期mod=(mod+1)%2;num=5000; //自动返回时间界面}key2=key1;} //键值保存。释放按键用}///////////////////////////////////////********************闹铃响一分钟****************************/void CLOCK(){ if((clock1[0]==hour)(clock1[1]==minute)(clock1[3])||((clock2[0]==hour)(clock2[1]==minute)(clock2[3]))){if(!clockdown) //没有睡懒觉则正常响铃BEEP=~BEEP;elseBEEP=1; //否则关闭闹铃} else{clockdown=0; //恢复闹铃BEEP=1; //关闭闹铃} }/////////////////////////////////////////main(){while(!Read_Nbyte_iic(SLAVE,0x50,clock1,3));while(!Read_Nbyte_iic(SLAVE,0x60,clock2,3));TimeInit(); //断电以后唤醒时钟Init_Ds1302();while(1){Get_Ds1302(DataTime); //读取时间TimerDis(); //段码处理KeySet(); //扫描按键if(!bflash) //如果没有进入设置时间则正常显示否则时间暂停{TimeToBin();}CLOCK(); //闹铃设置}}/*******************************************************************************************************************************/#ifndef __H_#define _DS1302_H_/*********************************************************************************/#includereg51.h>#includeintrins.h>#define uchar unsigned char#define uint unsigned intsbit RST = P3^4;sbit SCLK = P3^5;sbit IO = P3^6;/********以下是函数声明********/void Ds1302_Write_Byte(uchar ch); //写一字节数据函数声明uchar Ds1302_Read_Byte(); //读一字节数据函数声明void Write_Ds1302(uchar cmd,uchar indata); //写DS1302函数声明uchar Read_Ds1302(uchar addr); //读DS1302函数声明void Set_Ds1302(uchar *str); //设置时钟数据地址 格式为: 秒 分 时 日 月 星期 年void Get_Ds1302(uchar *str); //读当前时间函数声明void Init_Ds1302(); //DS1302初始化函数声明/********以下是写一字节数据函数********/void Ds1302_Write_Byte(uchar ch){uchar n;EA=0;for(n=0;n8;n++){SCLK=0; //写时低电平改变数据if(ch0x01)IO=1;elseIO=0;SCLK=1; //高电平把数据写入DS1302_nop_();_nop_();ch=ch>>1;}EA=1;}/********以下是读一字节数据函数********/uchar Ds1302_Read_Byte() {uchar n,temp=0;EA=0;IO=1; for(n=0;n8;n++){SCLK=1;if(IO)temp|=0x80;elsetemp=0x7f;SCLK=0; //产生下跳沿temp=temp>>1;}EA=1;return (temp);}/********写DS1302函数, 往DS1302的某个地址写入数据 ********/void Write_Ds1302(uchar cmd,uchar indata){SCLK=0;RST=1;Ds1302_Write_Byte(cmd); Ds1302_Write_Byte(indata);SCLK=0;RST=0;}/********读DS1302函数,读DS1302某地址的的数据********/uchar Read_Ds1302(uchar addr){uchar backdata;RST=0;SCLK=0;RST=1;Ds1302_Write_Byte(addr); //先写地址backdata=Ds1302_Read_Byte(); //然后读数据SCLK=0;RST=0;return (backdata);}/********设置初始时间函数********/void Set_Ds1302(uchar *str){uchar n,addr = 0x80;Write_Ds1302(0x8e,0x00); //写控制字,允许写操作for(n=0;n7;n++){Write_Ds1302(addr,*str);addr=addr+2;str++;}Write_Ds1302(0x8e,0x80); //写保护,不允许写}/********读取当前时间函数********/void Get_Ds1302(uchar *str){uchar n,addr = 0x81;for(n=0;n7;n++){str[n]=Read_Ds1302(addr);addr+=2;}}/************初始化时间********************/void Init_Ds1302(){RST=0;SCLK=0;RST=1;Write_Ds1302(0x80,0x00); //写秒寄存器Write_Ds1302(0x90,0xab); //写充电器Write_Ds1302(0x8e,0x80); //写保护控制字,禁止写}///////////////////////////////////////#endif/***********************************************************************************************************************/#ifndef _KEY_H_#define _KEY_H_/****************************************************/#define KEYIO P1 //定义键盘的输入口unsigned char code KeyTab[17]="123A456B789C*0#D"; //键盘查表/***********************************************/void delay_ms(unsigned int time) //误差 -0.000000000003us{unsigned char a,b;while(time--){for(b=102;b>0;b--)for(a=3;a>0;a--);}}/**************************************************////////////////////////////////////////////////unsigned char KeyRvs(void) //反转法{unsigned char temH, temL, key;delay_ms(10); //两次扫描间隔为10ms,消除抖动导致的误操作KEYIO = 0x0f; temL = KEYIO;//高四位先输出0;读入,低四位含有按键信息KEYIO = 0xf0; temH = KEYIO;//然后反转输出0;读入,高四位含有按键信息switch(temL){case 0x0e: key = 0; break;case 0x0d: key = 1; break;case 0x0b: key = 2; break;case 0x07: key = 3; break;default: return 16;//按下的不是上述按键,就当是没有按键}switch(temH){case 0xe0: return key;case 0xd0: return (key + 4);case 0xb0: return (key + 8);case 0x70: return (key + 12);default: return 16;//按下的不是上述按键,就当是没有按键}}/**********************************************************/ #endif//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////#ifndef _IIC_H#define _IIC_H_/***************************************************/#includeintrins.h>#define uchar unsigned char#define uint unsigned int#define SLAVE 0xa0 //IIC器件地址 注意全部接地#define Rslave SLAVE+1 //送读控制字sbit SDA=P3^0; //IIC数据接口sbit SCL=P3^1; //IIC时钟接口////////////////////////////////////////////////////////void delay_iic(uint time){for(time;time>0;time--);}///////////////////////////////////////void start_iic(){SDA=1;SCL=1;delay_iic(10);SDA=0;delay_iic(10);SCL=0;}void stop_iic(){SDA=0;SCL=1;delay_iic(10);SDA=1;delay_iic(10);SCL=0;}void ack_iic(){SDA=0;SCL=1;delay_iic(10);SCL=0;SDA=1;}void nack_iic(){SDA=1;SCL=1;delay_iic(10);SCL=0;SDA=0;}////////////////////////* write 1 byte *//////////////////////void write_byte(uchar ch){uchar i;for(i=0;i8;i++){if(ch0x80)SDA=1;elseSDA=0;SCL=1;delay_iic(10);SCL=0;ch=ch1;}SDA=1;SCL=1;delay_iic(10);if(SDA==1)F0=0;elseF0=1;SCL=0;}///////////////////////////* read 1 byte *////////////////////////uchar read_byte(){uchar i;uchar r=0;SDA=1;for(i=0;i8;i++){r=r1;SCL=1;delay_iic(10);if(SDA==1)r++;SCL=0;}return r;}/***********************写一个字节**************************bit Write_Byte_iic(uchar addr,uchar ch){start_iic(); //产生起始信号write_byte(SLAVE); //发送从器件地址if(F0==0) return 0; //检查应答位write_byte(addr); //发送目的地址if(F0==0) return 0;write_byte(ch); //发送8为数据if(F0==0) return 0;stop_iic(); //停止信号return 1;}/********************读一个字节***************************uchar Read_Byte_iic(uchar addr){ uchar ch; start_iic(); //启动IICwrite_byte(SLAVE); //写器件地址if(F0==0)return 0;write_byte(addr); //写读取的地址if(F0==0)return 0;start_iic(); //再次产生起始信号,不能少write_byte(Rslave); //送读控制字if(F0==0)return 0;ch=read_byte(); //读出指定单元的内容nack_iic(); //非应答信号stop_iic(); //停止IICreturn (ch); }************************************************************/////////////////////////////////////////////////////////////bit Read_Nbyte_iic(uchar slave,uint addr,uchar *str,uchar numb){uchar i;start_iic();write_byte(slave); //write iic addrif(F0==0)return 0;write_byte(addr); //write data addrif(F0==0)return 0;start_iic(); //再次产生起始信号,不能少write_byte(Rslave); //送读控制字if(F0==0)return 0;for(i=0;inumb-1;i++) //{*str=read_byte();ack_iic();str++;}*str=read_byte();nack_iic();stop_iic();return(1);}/////////////////////////* write n byte *////////////////////////////bit Write_Nbyte_iic(uchar slave,uint addr,uchar *str,uchar numb){uchar i;start_iic();write_byte(slave); //write iic addrif(F0==0)return 0;write_byte(addr); //write data addrif(F0==0)return 0;for(i=0;inumb;i++) //write data{write_byte(*str);if(F0==0)return 0;str++;}stop_iic(); //stop iicreturn(1);}/////////////////////////////////////////////////////////////////#endif


评论


相关推荐

技术专区

关闭