天天看点

51单片机+ds1302+lcd1602简易电子时钟(带闹钟功能)

51单片机+ds1302+lcd1602简易电子时钟(带闹钟功能)

51单片机+ds1302+lcd1602简易电子时钟(带闹钟功能)
  • AT89C52

    LCD1602

    DS1302

    speaker

  • Proteus

    仿真

实例代码

#include<reg52.H>
#include<INTRINS.H>

#define TIME (0X10000-50000)
#define FLAG 0XEF		//闹钟标志
//引脚连接图
sbit rst=P3^5;
sbit clk=P3^4;
sbit dat=P3^3;
sbit rs=P1^5;
sbit rw=P1^6;
sbit e=P1^7;
sbit DQ=P1^4;        
sbit P3_2=P3^2;

sbit ACC_7=ACC^7;
//全局变量及常量定义
unsigned char i=20,j,time1[16];	
unsigned char alarm[2],time2[15],time[3];
unsigned char code Day[]={31,28,31,30,31,30,31,31,30,31,30,31};//12个月的最大日期(非闰年)
//音律表
unsigned int code table1[]={64260,64400,64524,64580,64684,64777,
64820,64898,64968,65030,65058,65110,65157,65178,65217};
//发声部分的延时时间
unsigned char code table2[]={0x82,1,0x81,0xf4,0xd4,0xb4,0xa4,
0x94,0xe2,1,0xe1,0xd4,0xb4,0xc4,0xb4,4,0};
//LCD自建字
unsigned char code tab[]={0x10,0x11,0x12,0x1c,0x1c,0x12,0x11,0x11,
0x08,0x0f,0x12,0x0f,0x0a,0x1f,0x02,0x02,//年
0x0f,0x09,0x0f,0x09,0x0f,0x09,0x11,0x00,//月
0x0f,0x09,0x09,0x0f,0x09,0x09,0x0f,0x00};//日 

unsigned char code ditab[16]={0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09};
//闹钟中用的全局变量
unsigned char th1,tl1;
unsigned char temp_data[2]={0x00,0x00};               // 读出温度暂放
bit flag;		//18b20存在标志位
/***********11微秒延时函数**********/
void delay(unsigned int t)
{
	for(;t>0;t--);
}
/***********18B20复位函数**********/
void RST18B20(void)
{
	unsigned char i;
	DQ=1;_nop_();_nop_();
	DQ=0;    //
	delay(50); // 550us
	DQ=1;    // 
	delay(6);  // 66us
	for(i=0;i<0x30;i++)
	{
		if(!DQ)
			goto d1;			
	}
	flag=0;		//清标志位,表示ds1820不存在
	DQ=1;
	return;
d1:	delay(45);    //延时500us
	flag=1;
	DQ=1;		//置标志位,表示ds1820存在
} 
/**********18B20写命令函数*********/
//向 1-WIRE 总线上写一个字节
void Write1Byte18B20(unsigned char val)
{
	unsigned char i;
	for (i=8; i>0; i--) //
	{
		DQ=1;_nop_();_nop_(); 
		DQ=0;_nop_();_nop_();_nop_();_nop_();_nop_();//5us
		DQ=val&0x01;      //最低位移出
		delay(6);           //66us
		val=val/2;          //右移一位
	}
	DQ=1;
	delay(1);  
}
/*********18B20读1个字节函数********/
//从总线上读取一个字节
unsigned char Read1Byte18B20(void)
{
	unsigned char i;
	unsigned char value=0;
	for (i=8;i>0;i--)
	{
		DQ=1;_nop_();_nop_();
		value>>=1;
		DQ=0;             //
		_nop_();_nop_();_nop_();_nop_();   //4us
		DQ=1;_nop_();_nop_();_nop_();_nop_();   //4us 
		if(DQ)
			value|=0x80;
		delay(6);           //66us
	}
	DQ=1;
	return(value);
}
/***********读出温度函数**********/
void Read18B20()
{
	RST18B20();       			//总线复位
	if(!flag)		//判断ds1820是否存在?若ds18b20不存在则返回
		return;				
		
	//Write1Byte18B20(0xCC); 			// Skip ROM
	//Write1Byte18B20(0x44); 			// 发转换命令
	//delay(70);
	
	Write1Byte18B20(0xCC); 			//发Skip ROM命令
	Write1Byte18B20(0xBE); 			//发读命令
	temp_data[0]=Read1Byte18B20();   //温度低8位
	temp_data[1]=Read1Byte18B20();   //温度高8位	
	RST18B20();
	Write1Byte18B20(0xCC); 			// Skip ROM
	Write1Byte18B20(0x44); 			// 发转换命令
}
/***********温度数据处理函数**********/
void DealTempData()
{
	unsigned char n=0,m;       
	if(temp_data[1]>127)//负温度求补码
	{
		temp_data[1]=(256-temp_data[1]);
		temp_data[0]=(256-temp_data[0]);
		n=1;
	}
	time2[13]=ditab[temp_data[0]&0x0f]+'0';
	time2[12]='.';
	m=((temp_data[0]&0xf0)>>4)|((temp_data[1]&0x0f)<<4);//
	if(n)
	{
		m-=16;
	}
	time2[9]=m/100+'0';
	time2[11]=m%100;
	time2[10]=time2[11]/10+'0';
	time2[11]=time2[11]%10+'0';
	if(time2[9]=='0')//最高位为0时都不显示
	{
		time2[9]=0x20;	
		if(n)//负温度时最高位显示"-"
		{
			time2[9]='-';
		}
		if(time2[10]=='0')
		{
			if(n)
			{
				time2[10]='-';
				time2[9]=0x20;
			}
			else
				time2[10]=0x20;
			if(time2[11]=='0'&&time2[13]=='0')
				time2[11]=time2[12]=0x20;
		}			
	}
}
void delay1ms(unsigned char time)		//延时1ms
{
	unsigned char i,j;
	for(i=0;i<time;i++)
	{
		for(j=0;j<110;j++);
	}
}

//使能1602
void EnableLCD()
{
	rs=0;
	rw=0;
	e=0;
	delay1ms(3);
	e=1;
}
//写LCD函数
void WriteLCD(unsigned char i)
{
	P0=i;
	rs=1;
	rw=0;
	e=0;
	delay1ms(2);
	e=1;
}
//写LCD内部地址函数
void WriteLCDRAM(unsigned char data *address,m)
{
	unsigned char i,j;
	for(i=0;i<m;i++,address++)
	{
		j=*address;
		WriteLCD(j);
	}
}
//LCD显示
void LCDSHOW()
{
	P0=0XC;				//显示器开、光标关
	EnableLCD();
	P0=0x80;			//写入显示起始地址
	EnableLCD();
	WriteLCDRAM(time1,16);
	P0=0xc1;			//写入显示起始地址
	EnableLCD();
	WriteLCDRAM(time2,15);
}
//自建字函数库
void DesignHZ()
{
	unsigned char i;
	P0=0x40;
	EnableLCD();
	for(i=0;i<32;i++)
	{
		WriteLCD(tab[i]);
		delay1ms(2);	
	}
}

//写DS1302子程序
void WriteDS1302(unsigned char address)
{
	unsigned char i;
	clk=0;
	_nop_();
	rst=1;
	_nop_();
	for(i=0;i<8;i++)
	{
		dat=address&1;
		_nop_();
		clk=1;
		address>>=1;
		clk=0;
	}
}
//读DS1302子程序
unsigned char ReadDS1302()
{
	unsigned char i,j=0;
	for(i=0;i<8;i++)
	{
		j>>=1;
		_nop_();
		clk=0;
		_nop_();
		if(dat)
			j|=0x80;
		_nop_();
		clk=1;
	}
	return(j);
}
//部分显示数据初始化
void TimeInit()
{
	time1[1]=time1[13]=time2[8]=time2[9]=time2[10]=0x20,time2[14]=0;
	time1[6]=1,time1[9]=2,time1[12]=3,time1[2]='2',time1[3]='0';
	time1[14]='W',time2[2]=time2[5]=':';
	WriteDS1302(0xc1);
	alarm[0]=ReadDS1302();
	rst=0;
	WriteDS1302(0xc3);
	alarm[1]=ReadDS1302();
	rst=0;
	WriteDS1302(0xc5);
	time1[0]=ReadDS1302();
	rst=0;
}
//读取时间
void ReadTime()
{
	unsigned char i,m,n;
	WriteDS1302(0x8d);			//读取年份
	m=ReadDS1302();
	rst=0;
	time1[4]=m/16+0x30;
	time1[5]=m%16+0x30;
	WriteDS1302(0x8b);			//读取星期
	m=ReadDS1302();
	rst=0;
	time1[15]=m+0x30;
	for(i=7,n=0x89;i<11;i+=3,n-=2)	//读取月份和日期
	{
		WriteDS1302(n);
		m=ReadDS1302();
		rst=0;
		time1[i]=m/16+0x30;
		time1[i+1]=m%16+0x30;
	}
	for(m=0,i=0,n=0x85;i<7;i+=3,n-=2,m++)	//读取时,分,秒
	{
		WriteDS1302(n);
		time[m]=ReadDS1302();
		rst=0;
		time2[i]=time[m]/16+0x30;
		time2[i+1]=time[m]%16+0x30;
	}
}
void time0() interrupt 1 using 1
{
	i--;
	if(i==0)
	{
		if(j!=0)
			j--;		 
		i=20;
	}
	TH0=TIME/256,TL0=TIME%256;		
}
//闹钟部分
void intime1() interrupt 3
{
	TH1=th1,TL1=tl1;
	P3_2=!P3_2;
}
//显示闹钟设置数据
void showalarm()
{
	unsigned char i,j,a,b,n;
	ET1=1;
	for(j=0;j<6;j++)
	{
		i=0;
		while(1)
		{
			a=table2[i];
			if(a==0)
				break;
			b=a&0xf;
			a>>=4; 
			if(a==0)
			{
				TR1=0;
				goto  D1;
			}
			a=((--a)<<1)/2;
			TH1=th1=table1[a]/256,TL1=tl1=table1[a]%256;
			TR1=1;
D1:			do
			{
				b--;
				for(n=0;n<3;n++)
				{
					ReadTime();
					LCDSHOW();
					P2=0xf7;
					if(P2==0xe7)
					{
						P3_2=0;
						delay1ms(100);
						P3_2=1;
						if(P2==0xe7)
						{
							TR1=0;
							ET1=0;
							return;
						}	
					}
				}
			}while(b!=0);
			i++;				
		}
		TR1=0;	   	
	}
	ET1=0;
}
//根据日期的变动自动调整星期
unsigned char setweek()
{
	unsigned char i=5,j,n;
	j=(time1[4]&0xf)*10+(time1[5]&0xf);
	n=j/4;
	i=i+5*n;
	n=j%4;
	if(n==1)
		i+=2;
	else if(n==2)
		i+=3;
	else if(n==3)
		i+=4;
	j=(time1[7]&0xf)*10+(time1[8]&0xf);
	if(j==2)
		i+=3;
	else if(j==3)
		i+=3;	
	else if(j==4)
		i+=6;	
	else if(j==5)
		i+=1;	
	else if(j==6)
		i+=4;	
	else if(j==7)
		i+=6;	
	else if(j==8)
		i+=2;	
	else if(j==9)
		i+=5;
	else if(j==11)
		i+=3;	
	else if(j==12)
		i+=5;
	if(n==0)
		if(j>2)	
			i++;	
	j=(time1[10]&0xf)*10+(time1[11]&0xf);
	i+=j;
	i%=7;
	if(i==0)
		i=7;
	return(i);	
}
//设置时间
void settime()
{
	unsigned char i=0x85,year,month,day,n;
	time2[6]=time2[7]=0x30,time1[14]=time1[15]=0x20;
	LCDSHOW();
	while(1)
	{		
		P0=0xe;			//显示器开、光标开
		EnableLCD();
		P0=i;			//定光标
		EnableLCD();
		P2=0xf7;
		if(P2!=0XF7)
		{
			delay1ms(10);//延时0.1s去抖动
			P3_2=0;
			delay1ms(90);
			P3_2=1;
			if(P2!=0XF7)
			{
				
				j=7;
				if(P2==0X77)
				{			delay1ms(10);//延时0.1s去抖动
			P3_2=0;
			delay1ms(90);
			P3_2=1;
					i+=3;
					if(i==0x8e)
						i=0xc2;
					else if(i>0xc5)
						i=0x85;
					
				}
				else if(P2==0xb7)
				{
								delay1ms(10);//延时0.1s去抖动
			P3_2=0;
			delay1ms(90);
			P3_2=1;
					year=(time1[4]&0xf)*10+(time1[5]&0xf);
					month=(time1[7]&0xf)*10+(time1[8]&0xf);
					day=(time1[10]&0xf)*10+(time1[11]&0xf);
					if(i==0x85)
					{
						year++;
						if(year>99)
							year=0;
						if((year%4)!=0)
							if(month==2&&day==29)
								day=28;
							while(P2==0XF7);
					}
					else if(i==0x88)
					{
						month++;
						if(month>12)
							month=1;
						if(day>Day[month-1])
						{
							day=Day[month-1];
							if(month==2&&(year%4)==0)	
								day=29;
						}												
					}
					else if(i==0x8b)
					{
						day++;
						if(day>Day[month-1])
						{
							if(month==2&&(year%4)==0)
							{
								if(day>29)
									day=1;
							}
							if(month!=2)
								day=1;
						}
					}
					else if(i==0xc2)
					{
						n=(time2[0]&0xf)*10+(time2[1]&0xf);
						n++;
						if(n>23)
							n=0;
						time2[0]=n/10+0x30;
						time2[1]=n%10+0x30;
					}
					else
					{
						n=(time2[3]&0xf)*10+(time2[4]&0xf);
						n++;
						if(n>59)
							n=0;
						time2[3]=n/10+0x30;
						time2[4]=n%10+0x30;
					}
					time1[4]=year/10+0x30;
					time1[5]=year%10+0x30;
					time1[7]=month/10+0x30;
					time1[8]=month%10+0x30;
					time1[10]=day/10+0x30;
					time1[11]=day%10+0x30;
					LCDSHOW();
				}
				else if(P2==0xd7)
				{
								delay1ms(10);//延时0.1s去抖动
			P3_2=0;
			delay1ms(90);
			P3_2=1;
					WriteDS1302(0x8c);
					WriteDS1302((time1[4]&0xf)*16+(time1[5]&0xf));
					rst=0;
					WriteDS1302(0x8a);
					WriteDS1302(setweek());
					rst=0;
					for(i=7,n=0x88;i<11;i+=3,n-=2)
					{	
						WriteDS1302(n);
						WriteDS1302((time1[i]&0xf)*16+(time1[i+1]&0xf));
						rst=0;
					}
					for(i=0;i<7;i+=3,n-=2)
					{
						WriteDS1302(n);
						WriteDS1302((time2[i]&0xf)*16+(time2[i+1]&0xf));
						rst=0;
					}
					TR0=0;
					time1[14]='W';
					return;
				}
				else
				{
					TR0=0;
					time1[14]='W';
					return;
				}
				while(P2!=0XF7);
			}
		}	
		if(j==0)
		{	
			TR0=0;
			time1[14]='W';
			return;
		}
	}
}
//设置闹钟
void setalarm()
{
	unsigned char i,n;
	for(i=1;i<16;i++)
	{
		time1[i]=0x20;
	}	
	time2[0]=alarm[0]/16+0x30;
	time2[1]=(alarm[0]&0xf)+0x30;
	time2[3]=alarm[1]/16+0x30;
	time2[4]=(alarm[1]&0xf)+0x30;
	time2[6]=time2[7]=0x30;
	LCDSHOW();
	i=0xc2;
	while(1)
	{
		P0=0xe;			//显示器开、光标开
		EnableLCD();
		P0=i;			//定光标
		EnableLCD();
		P2=0xf7;
		if(P2!=0XF7)
		{
			delay1ms(100);				//延时0.1s去抖动
			if(P2!=0XF7)
			{
				j=7;
				if(P2==0X77)
				{
					i+=3;
					if(i>0xc5)
						i=0xc2;
				}
				else if(P2==0xb7)
				{
					if(i==0xc2)
					{
						n=(time2[0]&0xf)*10+(time2[1]&0xf);
						n++;
						if(n>23)
							n=0;
						time2[0]=n/10+0x30;
						time2[1]=n%10+0x30;
					}
					else
					{
						n=(time2[3]&0xf)*10+(time2[4]&0xf);
						n++;
						if(n>59)
							n=0;
						time2[3]=n/10+0x30;
						time2[4]=n%10+0x30;
					}
					LCDSHOW();
				}
				else if(P2==0xd7)
				{
					WriteDS1302(0xc0);
					WriteDS1302((time2[0]&0xf)*16+(time2[1]&0xf));
					rst=0;
					WriteDS1302(0xc2);
					WriteDS1302((time2[3]&0xf)*16+(time2[4]&0xf));
					rst=0;
					time1[0]=FLAG;
					WriteDS1302(0xc4);
					WriteDS1302(time1[0]);
					rst=0;
					TR0=0;
					TimeInit();
					return;
				}
				else
				{
					TR0=0;
					TimeInit();
					return;
				}
			}
		}	
		if(j==0)
		{	
			TR0=0;
			TimeInit();
			return;
		}
	}
}
void main()
{
	IE=0X82;
	TMOD=0x11;
	WriteDS1302(0x8E);			//禁止写保护
	WriteDS1302(0);
	rst=0;
	P0=1;				//清屏并光标复位
	EnableLCD();
	P0=0X38;			//设置显示模式:8位2行5x7点阵
	EnableLCD();
	P0=6;				//文字不动,光标自动右移
	EnableLCD();
	DesignHZ();			//自建字
	TimeInit();
	while(1)
	{	
		ReadTime();				//读取时间
		DealTempData();        	//处理温度数据
		LCDSHOW();				//显示时间
		if(time1[0]!=0x20)
			if(time[0]==alarm[0])
				if(time[1]==alarm[1])
					if(time[2]==0)
						showalarm();
		P2=0xf7;
		if((P2&0XF0)!=0XF0)
		{
			delay1ms(100);				//延时0.1s去抖动
			if((P2&0XF0)!=0XF0)
			{
				j=7;
				TH0=TIME/256,TL0=TIME%256;
				TR0=1;
				if(P2==0x77)
				{
					settime();
				}
				else if(P2==0XB7)
				{
					setalarm();
				}
				else if(P2==0XD7)
				{
					TR0=0;
					if(time1[0]==FLAG)
					{time1[0]=0x20;
								delay1ms(10);//延时0.1s去抖动
			P3_2=0;
			delay1ms(90);
			P3_2=1;}
					else
					
						{time1[0]=FLAG;
								delay1ms(10);//延时0.1s去抖动
			P3_2=0;
			delay1ms(90);
			P3_2=1;
																delay1ms(10);//延时0.1s去抖动
			P3_2=0;
			delay1ms(90);
			P3_2=1;
								delay1ms(10);//延时0.1s去抖动
			P3_2=0;
			delay1ms(90);
			P3_2=1;

				}
					
					WriteDS1302(0xc4);
					WriteDS1302(time1[0]);
					rst=0;
				}
			}
		}
		
		delay1ms(100);	
	}
}
           

源码资源

baidu链接:https://pan.baidu.com/s/1CPqzXV6T9aTHPzqmY_dR5w 
提取码:rokk
           

继续阅读