基于51单片机的钟表闹钟万年历气温显示仿真

仿真图:

在这里插入图片描述

芯片/模块的特点:

DS18B20特点:

  1. 单总线接口:DS18B20使用单总线接口进行通信,只需要一个引脚就可以连接多个传感器,简化了电路设计和连接。
  2. 数字输出:DS18B20以数字形式输出温度值,不需要额外的模数转换器。它使用12位的分辨率来表示温度值,可以实现高精度的温度测量。
  3. 高精度:DS18B20可以提供从-55°C到+125°C的温度测量范围,并具有±0.5°C的温度精度。因此,在许多应用中,它可以提供可靠和准确的温度测量结果。
  4. 多功能性:除了测量温度,DS18B20还可以执行其他功能,如温度报警功能。它可以设置上下限温度阈值,并在温度超过或低于这些阈值时触发报警。
  5. 低功耗:DS18B20采用低功耗设计,工作电流极低,只需要很少的能量来进行温度测量和通信。
  6. 耐用性:DS18B20具有良好的耐用性和可靠性,其封装材料和结构设计使其适用于各种环境条件下的应用。

DS1302特点:
高精度时间计数:DS1302能够提供高精度的实时时钟计数,可以记录年、月、日、星期、小时、分钟和秒等时间信息。它内部集成了晶体振荡器,提供稳定的时钟信号。

低功耗设计:DS1302采用低功耗设计,可以在低功耗模式下运行,有效延长电池寿命。即使在停电情况下,它也能保持时间数据,并通过外部连接电池继续提供计时功能。

串行接口:DS1302通过串行实时时钟接口(SPI)进行通信和控制。使用少数几个引脚,可以与主控器件进行数据交换和时钟同步。

容易集成:DS1302集成了时钟计数和RAM存储器功能,并具有简单的接口和命令,容易与各种微控制器和单片机集成。它不需要复杂的控制信号,可以通过简单的读写命令进行操作。

可编程控制功能:DS1302具有可编程的控制功能,可以设置闹钟、写保护等特殊功能。它还支持多种时间格式的选择,例如24小时制或12小时制。

温度补偿:DS1302内置温度补偿功能,可以校正温度对时钟频率的影响,提高时钟计数的准确性。

高稳定性和抗震动能力:DS1302具有高稳定性和抗震动能力,适用于各种工业和消费类应用场景。

主程序:

#include <reg52.h>
#include <intrins.h>

#define uchar unsigned char	// 以后unsigned char就可以用uchar代替
#define uint  unsigned int	// 以后unsigned int 就可以用uint 代替

sfr ISP_DATA  = 0xe2;				// 数据寄存器
sfr ISP_ADDRH = 0xe3;				// 地址寄存器高八位
sfr ISP_ADDRL = 0xe4;				// 地址寄存器低八位
sfr ISP_CMD   = 0xe5;				// 命令寄存器
sfr ISP_TRIG  = 0xe6;				// 命令触发寄存器
sfr ISP_CONTR = 0xe7;				// 命令寄存器

sbit LcdRs_P    = P2^5;       // 1602液晶的RS管脚       
sbit LcdRw_P    = P2^6;       // 1602液晶的RW管脚 
sbit LcdEn_P    = P2^7;       // 1602液晶的EN管脚
sbit RST_P      = P1^4;				// 时钟芯片DS1302的RST管脚
sbit SDA_P      = P1^6;				// 时钟芯片DS1302的SDA管脚
sbit SCK_P      = P1^5;				// 时钟芯片DS1302的SCK管脚
sbit KeySet_P   = P3^3;				// 设置时间按键
sbit KeyClock_P = P3^5;				// 设置闹钟按键
sbit KeyDown_P  = P3^6;				// 减按键
sbit KeyUp_P    = P3^4;				// 加按键
sbit Buzzer_P   = P2^1;				// 蜂鸣器
sbit DQ         = P1^2;				// DS18B20传感器的引脚定义


uchar TimeBuff[7]={17,9,1,6,18,30,40};				// 时间数组,默认2017年9月1日,星期五,18:30:40
// TimeBuff[0] 代表年份,范围00-99
// TimeBuff[1] 代表月份,范围1-12
// TimeBuff[2] 代表日期,范围1-31
// TimeBuff[3] 代表星期,范围1-7,1是星期天,2是星期一... ...
// TimeBuff[4] 代表小时,范围00-23
// TimeBuff[5] 代表分钟,范围00-59
// TimeBuff[6] 代表秒钟,范围00-59


uchar Clock_Hour;					// 闹钟的小时
uchar Clock_Minute;				// 闹钟的分钟
uchar Clock_Swt;					// 闹钟的开关
uchar Buzzer_Flag=0;			// 蜂鸣器工作标志



/*********************************************************/
// 单片机内部EEPROM不使能
/*********************************************************/
void ISP_Disable()
{
	ISP_CONTR = 0;
	ISP_ADDRH = 0;
	ISP_ADDRL = 0;
}


/*********************************************************/
// 从单片机内部EEPROM读一个字节,从0x2000地址开始
/*********************************************************/
unsigned char EEPROM_Read(unsigned int add)
{
	ISP_DATA  = 0x00;
	ISP_CONTR = 0x83;
	ISP_CMD   = 0x01;
	ISP_ADDRH = (unsigned char)(add>>8);
	ISP_ADDRL = (unsigned char)(add&0xff);
	// 对STC89C51系列来说,每次要写入0x46,再写入0xB9,ISP/IAP才会生效
	ISP_TRIG  = 0x46;	   
	ISP_TRIG  = 0xB9;
	_nop_();
	ISP_Disable();
	return (ISP_DATA);
}


/*********************************************************/
// 往单片机内部EEPROM写一个字节,从0x2000地址开始
/*********************************************************/
void EEPROM_Write(unsigned int add,unsigned char ch)
{
	ISP_CONTR = 0x83;
	ISP_CMD   = 0x02;
	ISP_ADDRH = (unsigned char)(add>>8);
	ISP_ADDRL = (unsigned char)(add&0xff);
	ISP_DATA  = ch;
	ISP_TRIG  = 0x46;
	ISP_TRIG  = 0xB9;
	_nop_();
	ISP_Disable();
}


/*********************************************************/
// 擦除单片机内部EEPROM的一个扇区
// 写8个扇区中随便一个的地址,便擦除该扇区,写入前要先擦除
/*********************************************************/
void Sector_Erase(unsigned int add)	  
{
	ISP_CONTR = 0x83;
	ISP_CMD   = 0x03;
	ISP_ADDRH = (unsigned char)(add>>8);
	ISP_ADDRL = (unsigned char)(add&0xff);
	ISP_TRIG  = 0x46;
	ISP_TRIG  = 0xB9;
	_nop_();
	ISP_Disable();
}


/*********************************************************/
// 毫秒级的延时函数,time是要延时的毫秒数
/*********************************************************/
void DelayMs(uint time)
{
	uint i,j;
	for(i=0;i<time;i++)
		for(j=0;j<112;j++);
}


/*********************************************************/
// 延时15微秒
/*********************************************************/
void Delay15us(void)
{
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}


/*********************************************************/
// 复位DS18B20(初始化)
/*********************************************************/
void DS18B20_ReSet(void)
{
	uchar i;
	DQ=0;
	i=240;
	while(--i);
	DQ=1;
	i=30;
	while(--i);
	while(~DQ);
	i=4;
	while(--i);
}


/*********************************************************/
// 向DS18B20写入一个字节
/*********************************************************/
void DS18B20_WriteByte(uchar dat)
{
	uchar j;
	uchar btmp;
	
	for(j=0;j<8;j++)
	{
		btmp=0x01;
		btmp=btmp<<j;
		btmp=btmp&dat;
		
		if(btmp>0)		// 写1
		{
			DQ=0;
			Delay15us();
			DQ=1;
			Delay15us();
			Delay15us();
			Delay15us();
			Delay15us();
		}
		else			// 写0
		{
			DQ=0;
			Delay15us();
			Delay15us();
			Delay15us();
			Delay15us();
			DQ=1;
			Delay15us();
		}
	}
}


/*********************************************************/
// 读取温度值
/*********************************************************/
int DS18B20_ReadTemp(void)
{
	uchar j;
	int b,temp=0;	

	DS18B20_ReSet();							// 产生复位脉
	DS18B20_WriteByte(0xcc);			// 忽略ROM指令
	DS18B20_WriteByte(0x44);			// 启动温度转换指令

	DS18B20_ReSet();							// 产生复位脉
	DS18B20_WriteByte(0xcc);			// 忽略ROM指令
	DS18B20_WriteByte(0xbe);			// 读取温度指令

	for(j=0;j<16;j++)							// 读取温度数量
	{						
		DQ=0;
		_nop_();
		_nop_();
		DQ=1;	
		Delay15us();
		b=DQ;
		Delay15us();
		Delay15us();
		Delay15us();
		b=b<<j;
		temp=temp|b;
	}
	
	temp=temp*0.0625*10;					// 合成温度值并放大10倍					
	return (temp);								// 返回检测到的温度值
}



/*********************************************************/
// 1602液晶写命令函数,cmd就是要写入的命令
/*********************************************************/
void LcdWriteCmd(uchar cmd)
{ 
	LcdRs_P = 0;
	LcdRw_P = 0;
	LcdEn_P = 0;
	P0=cmd;
	DelayMs(2);
	LcdEn_P = 1;    
	DelayMs(2);
	LcdEn_P = 0;	
}


/*********************************************************/
// 1602液晶写数据函数,dat就是要写入的数据
/*********************************************************/
void LcdWriteData(uchar dat)
{
	LcdRs_P = 1; 
	LcdRw_P = 0;
	LcdEn_P = 0;
	P0=dat;
	DelayMs(2);
	LcdEn_P = 1;    
	DelayMs(2);
	LcdEn_P = 0;
}


/*********************************************************/
// 1602液晶初始化函数
/*********************************************************/
void LcdInit()
{
	LcdWriteCmd(0x38);        // 16*2显示,5*7点阵,8位数据口
	LcdWriteCmd(0x0C);        // 开显示,不显示光标
	LcdWriteCmd(0x06);        // 地址加1,当写入数据后光标右移
	LcdWriteCmd(0x01);        // 清屏
}


/*********************************************************/
// 液晶光标定位函数
/*********************************************************/
void LcdGotoXY(uchar line,uchar column)
{
	// 第一行
	if(line==0)        
		LcdWriteCmd(0x80+column); 
	// 第二行
	if(line==1)        
		LcdWriteCmd(0x80+0x40+column); 
}


/*********************************************************/
// 液晶输出字符串函数
/*********************************************************/
void LcdPrintStr(uchar *str)
{
	while(*str!='\0')
			LcdWriteData(*str++);
}


/*********************************************************/
// 液晶显示内容的初始化
/*********************************************************/
void LcdShowInit()
{
	LcdGotoXY(0,0);
	LcdPrintStr("20  -  -        ");
	LcdGotoXY(1,0);
	LcdPrintStr("  :  :         C");
	LcdGotoXY(1,14);									// 温度单位摄氏度上面的圆圈符号
	LcdWriteData(0xdf);	
}



/*********************************************************/
// 液晶输出数字
/*********************************************************/
void LcdPrintNum(uchar num)
{
	LcdWriteData(num/10+48);		// 十位
	LcdWriteData(num%10+48); 		// 个位
}


/*********************************************************/
// 液晶显示星期
/*********************************************************/
void LcdPrintWeek(uchar week)
{
	switch(week)
	{
		case 1: LcdPrintStr(" Sun");	break;
		case 2: LcdPrintStr(" Mon");	break;
		case 3: LcdPrintStr("Tues");	break;
		case 4: LcdPrintStr(" Wed");	break;
		case 5: LcdPrintStr("Thur");	break;
		case 6: LcdPrintStr(" Fri");	break;
		case 7: LcdPrintStr(" Sat");	break;
		default:											break;
	}
}


/*********************************************************/
// 刷新时间显示
/*********************************************************/
void FlashTime()
{
	LcdGotoXY(0,2);										// 年份
	LcdPrintNum(TimeBuff[0]);
	LcdGotoXY(0,5);										// 月份
	LcdPrintNum(TimeBuff[1]);
	LcdGotoXY(0,8);										// 日期
	LcdPrintNum(TimeBuff[2]);
	LcdGotoXY(1,0);										// 小时
	LcdPrintNum(TimeBuff[4]);
	LcdGotoXY(1,3);										// 分钟
	LcdPrintNum(TimeBuff[5]);
	LcdGotoXY(1,6);										// 秒钟
	LcdPrintNum(TimeBuff[6]);
	LcdGotoXY(0,12);									// 星期	
	LcdPrintWeek(TimeBuff[3]);
}



/*********************************************************/
// 温度值的显示
/*********************************************************/
void LcdPrintTemp(int temp)
{
	if(temp<0)													
	{
		LcdWriteData('-');								// 显示负号	
		temp=0-temp;											// 负数转为正数	
	}
	else if(temp>999) 									// 显示百位
	{
		LcdWriteData(temp/1000+0x30);
	}
	else
	{
		LcdWriteData(' ');
	}
	LcdWriteData(temp%1000/100+0x30);		// 显示十位
	LcdWriteData(temp%100/10+0x30);			// 显示个位
	LcdWriteData('.');									// 显示小数点
	LcdWriteData(temp%10+0x30);					// 显示小数后一位小数
}



/*********************************************************/
// 初始化DS1302
/*********************************************************/
void DS1302_Init(void)
{
	RST_P=0;			// RST脚置低
	SCK_P=0;			// SCK脚置低
	SDA_P=0;			// SDA脚置低				
}



/*********************************************************/
// 从DS1302读出一字节数据
/*********************************************************/
uchar DS1302_Read_Byte(uchar addr) 
{
	uchar i;
	uchar temp;
	
	RST_P=1;								
	
	/* 写入目标地址:addr*/
	for(i=0;i<8;i++) 
	{     
		if(addr&0x01) 
			SDA_P=1;
		else 
			SDA_P=0;
		
		SCK_P=1;
		_nop_();
		SCK_P=0;
		_nop_();
		
		addr=addr>> 1;
	}
	
	/* 读出该地址的数据 */
	for(i=0;i<8;i++) 
	{
		temp=temp>>1;
		
		if(SDA_P) 
			temp|= 0x80;
		else 
			temp&=0x7F;
		
		SCK_P=1;
		_nop_();
		SCK_P=0;
		_nop_();
	}
	
	RST_P=0;
	
	return temp;
}



/*********************************************************/
// 向DS1302写入一字节数据
/*********************************************************/
void DS1302_Write_Byte(uchar addr, uchar dat)
{
	uchar i;
	
	RST_P = 1;
	
	/* 写入目标地址:addr*/
	for(i=0;i<8;i++) 
	{ 
		if(addr&0x01) 
			SDA_P=1;
		else 
			SDA_P=0;

		SCK_P=1;
		_nop_();
		SCK_P=0;
		_nop_();
		
		addr=addr>>1;
	}
	
	/* 写入数据:dat*/
	for(i=0;i<8;i++) 
	{
		if(dat&0x01) 
			SDA_P=1;
		else 
			SDA_P=0;
	
		SCK_P=1;
		_nop_();
		SCK_P=0;
		_nop_();
		
		dat=dat>>1;
	}
	
	RST_P=0;					
}



/*********************************************************/
// 向DS1302写入时间数据
/*********************************************************/
void DS1302_Write_Time() 
{
  uchar i;
	uchar temp1;
	uchar temp2;
	
	for(i=0;i<7;i++)			// 十进制转BCD码
	{
		temp1=(TimeBuff[i]/10)<<4;
		temp2=TimeBuff[i]%10;
		TimeBuff[i]=temp1+temp2;
	}
	
	DS1302_Write_Byte(0x8E,0x00);								// 关闭写保护 
	DS1302_Write_Byte(0x80,0x80);								// 暂停时钟 
	DS1302_Write_Byte(0x8C,TimeBuff[0]);				// 年 
	DS1302_Write_Byte(0x88,TimeBuff[1]);				// 月 
	DS1302_Write_Byte(0x86,TimeBuff[2]);				// 日 
	DS1302_Write_Byte(0x8A,TimeBuff[3]);				// 星期
	DS1302_Write_Byte(0x84,TimeBuff[4]);				// 时 
	DS1302_Write_Byte(0x82,TimeBuff[5]);				// 分
	DS1302_Write_Byte(0x80,TimeBuff[6]);				// 秒
	DS1302_Write_Byte(0x80,TimeBuff[6]&0x7F);		// 运行时钟
	DS1302_Write_Byte(0x8E,0x80);								// 打开写保护  
}




/*********************************************************/
// 从DS1302读出时间数据
/*********************************************************/
void DS1302_Read_Time()  
{ 
	uchar i;

	TimeBuff[0]=DS1302_Read_Byte(0x8D);						// 年 
	TimeBuff[1]=DS1302_Read_Byte(0x89);						// 月 
	TimeBuff[2]=DS1302_Read_Byte(0x87);						// 日 
	TimeBuff[3]=DS1302_Read_Byte(0x8B);						// 星期
	TimeBuff[4]=DS1302_Read_Byte(0x85);						// 时 
	TimeBuff[5]=DS1302_Read_Byte(0x83);						// 分 
	TimeBuff[6]=(DS1302_Read_Byte(0x81))&0x7F;		// 秒 

	for(i=0;i<7;i++)		// BCD转十进制
	{           
		TimeBuff[i]=(TimeBuff[i]/16)*10+TimeBuff[i]%16;
	}
}




/*********************************************************/
// 按键扫描(设置时间)
/*********************************************************/
void KeyScanf1()
{
	if(KeySet_P==0)
	{
		LcdWriteCmd(0x0f);			// 启动光标闪烁
		LcdGotoXY(0,3);					// 定位光标到年份闪烁
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeySet_P);				// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
		
		/* 调整年份 */
		while(1)
		{
			if(KeyDown_P==0)							// 如果减按键被下去
			{
				if(TimeBuff[0]>0)						// 判断年份是否大于0		
					TimeBuff[0]--;						// 是的话就减去1
				LcdGotoXY(0,2);							// 光标定位到年份的位置
				LcdPrintNum(TimeBuff[0]);		// 刷新显示改变后的年份
				LcdGotoXY(0,3);							// 定位光标到年份闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0)								// 如果加按键被下去
			{
				if(TimeBuff[0]<99)					// 判断年份是否小于99
					TimeBuff[0]++;						// 是的话就加上1
				LcdGotoXY(0,2);							// 光标定位到年份的位置
				LcdPrintNum(TimeBuff[0]);		// 刷新显示改变后的年份
				LcdGotoXY(0,3);							// 定位光标到年份闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeySet_P==0)
			{
				break;
			}
		}
		
		LcdGotoXY(0,6);					// 定位光标到月份闪烁
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeySet_P);				// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
			
		/* 调整月份 */
		while(1)
		{
			if(KeyDown_P==0)							// 如果减按键被下去
			{
				if(TimeBuff[1]>1)						// 判断月份是否大于1		
					TimeBuff[1]--;						// 是的话就减去1
				LcdGotoXY(0,5);							// 光标定位到月份的位置
				LcdPrintNum(TimeBuff[1]);		// 刷新显示改变后的月份
				LcdGotoXY(0,6);							// 定位光标到月份闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0)								// 如果加按键被下去
			{
				if(TimeBuff[1]<12)					// 判断月份是否小于12
					TimeBuff[1]++;						// 是的话就加上1
				LcdGotoXY(0,5);							// 光标定位到月份的位置
				LcdPrintNum(TimeBuff[1]);		// 刷新显示改变后的月份
				LcdGotoXY(0,6);							// 定位光标到月份闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeySet_P==0)
			{
				break;
			}
		}
		
		LcdGotoXY(0,9);					// 定位光标到日期闪烁
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeySet_P);				// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
		
		/* 调整日期 */
		while(1)
		{
			if(KeyDown_P==0)							// 如果减按键被下去
			{
				if(TimeBuff[2]>1)						// 判断日期是否大于1		
					TimeBuff[2]--;						// 是的话就减去1
				LcdGotoXY(0,8);							// 光标定位到日期的位置
				LcdPrintNum(TimeBuff[2]);		// 刷新显示改变后的日期
				LcdGotoXY(0,9);							// 定位光标到日期闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0)								// 如果加按键被下去
			{
				if(TimeBuff[2]<31)					// 判断日期是否小于31
					TimeBuff[2]++;						// 是的话就加上1
				LcdGotoXY(0,8);							// 光标定位到日期的位置
				LcdPrintNum(TimeBuff[2]);		// 刷新显示改变后的日期
				LcdGotoXY(0,9);							// 定位光标到日期闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeySet_P==0)
			{
				break;
			}
		}
		
		LcdGotoXY(0,15);				// 定位光标到星期闪烁
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeySet_P);				// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
		
		/* 调整星期 */
		while(1)
		{
			if(KeyDown_P==0)							// 如果减按键被下去
			{
				if(TimeBuff[3]>1)						// 判断星期是否大于1		
					TimeBuff[3]--;						// 是的话就减去1
				LcdGotoXY(0,12);						// 光标定位到星期的位置
				LcdPrintWeek(TimeBuff[3]);	// 刷新显示改变后的星期
				LcdGotoXY(0,15);						// 定位光标到星期闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0)								// 如果加按键被下去
			{
				if(TimeBuff[3]<7)						// 判断星期是否小于7
					TimeBuff[3]++;						// 是的话就加上1
				LcdGotoXY(0,12);						// 光标定位到星期的位置
				LcdPrintWeek(TimeBuff[3]);	// 刷新显示改变后的星期
				LcdGotoXY(0,15);						// 定位光标到星期闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeySet_P==0)
			{
				break;
			}
		}
		
		LcdGotoXY(1,1);					// 定位光标到小时闪烁
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeySet_P);				// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
		
		/* 调整小时 */
		while(1)
		{
			if(KeyDown_P==0)							// 如果减按键被下去
			{
				if(TimeBuff[4]>0)						// 判断小时是否大于0
					TimeBuff[4]--;						// 是的话就减去1
				LcdGotoXY(1,0);							// 光标定位到小时的位置
				LcdPrintNum(TimeBuff[4]);		// 刷新显示改变后的小时
				LcdGotoXY(1,1);							// 定位光标到小时闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0)								// 如果加按键被下去
			{
				if(TimeBuff[4]<23)					// 判断小时是否小于23
					TimeBuff[4]++;						// 是的话就加上1
				LcdGotoXY(1,0);							// 光标定位到小时的位置
				LcdPrintNum(TimeBuff[4]);		// 刷新显示改变后的小时
				LcdGotoXY(1,1);							// 定位光标到小时闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeySet_P==0)
			{
				break;
			}
		}
		
		LcdGotoXY(1,4);					// 定位光标到分钟闪烁
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeySet_P);				// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
		
		/* 调整分钟 */
		while(1)
		{
			if(KeyDown_P==0)							// 如果减按键被下去
			{
				if(TimeBuff[5]>0)						// 判断分钟是否大于0
					TimeBuff[5]--;						// 是的话就减去1
				LcdGotoXY(1,3);							// 光标定位到分钟的位置
				LcdPrintNum(TimeBuff[5]);		// 刷新显示改变后的分钟
				LcdGotoXY(1,4);							// 定位光标到分钟闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0)								// 如果加按键被下去
			{
				if(TimeBuff[5]<59)					// 判断分钟是否小于59
					TimeBuff[5]++;						// 是的话就加上1
				LcdGotoXY(1,3);							// 光标定位到分钟的位置
				LcdPrintNum(TimeBuff[5]);		// 刷新显示改变后的分钟
				LcdGotoXY(1,4);							// 定位光标到分钟闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeySet_P==0)
			{
				break;
			}
		}
		
		LcdGotoXY(1,7);					// 定位光标到秒钟闪烁
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeySet_P);				// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
		
		/* 调整秒钟 */
		while(1)
		{
			if(KeyDown_P==0)							// 如果减按键被下去
			{
				if(TimeBuff[6]>0)						// 判断秒钟是否大于0
					TimeBuff[6]--;						// 是的话就减去1
				LcdGotoXY(1,6);							// 光标定位到秒钟的位置
				LcdPrintNum(TimeBuff[6]);		// 刷新显示改变后的秒钟
				LcdGotoXY(1,7);							// 定位光标到秒钟闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0)								// 如果加按键被下去
			{
				if(TimeBuff[6]<59)					// 判断秒钟是否小于59
					TimeBuff[6]++;						// 是的话就加上1
				LcdGotoXY(1,6);							// 光标定位到秒钟的位置
				LcdPrintNum(TimeBuff[6]);		// 刷新显示改变后的秒钟
				LcdGotoXY(1,7);							// 定位光标到秒钟闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeySet_P==0)
			{
				break;
			}
		}
		
		/* 退出前的设置 */
		LcdWriteCmd(0x0C);			// 关闭光标闪烁
		DS1302_Write_Time();		// 把新设置的时间值存入DS1302芯片
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeySet_P);				// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
	}
}



/*********************************************************/
// 按键扫描(设置闹钟)
/*********************************************************/
void KeyScanf2()
{
	if(KeyClock_P==0)
	{
		LcdGotoXY(0,0);										// 液晶显示为闹钟设置的界面
		LcdPrintStr("Alarm Clock Set ");
		LcdGotoXY(1,0);				
		LcdPrintStr("     :          ");
		LcdGotoXY(1,3);										// 显示闹钟的小时
		LcdPrintNum(Clock_Hour);
		LcdGotoXY(1,6);										// 显示闹钟的分钟
		LcdPrintNum(Clock_Minute);
		LcdGotoXY(1,10);									// 显示闹钟状态
		if(Clock_Swt==0)
		{
			LcdPrintStr("OFF");
		}
		else
		{
			LcdPrintStr(" ON");
		}
		LcdGotoXY(1,4);										// 光标定位
		LcdWriteCmd(0x0f);								// 光标闪烁
		DelayMs(10);											// 延时等待,消除按键按下的抖动
		while(!KeyClock_P);								// 等待按键释放
		DelayMs(10);											// 延时等待,消除按键松开的抖动
		
		/* 调整闹钟小时 */
		while(1)
		{
			if(KeyDown_P==0)							// 如果减按键被下去
			{
				if(Clock_Hour>0)						// 判断闹钟小时是否大于0
					Clock_Hour--;							// 是的话就减去1
				LcdGotoXY(1,3);							// 光标定位到闹钟小时的位置
				LcdPrintNum(Clock_Hour);		// 刷新显示改变后的闹钟小时
				LcdGotoXY(1,4);							// 定位光标到闹钟小时闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0)								// 如果加按键被下去
			{
				if(Clock_Hour<23)						// 判断闹钟小时是否小于23
					Clock_Hour++;							// 是的话就加上1
				LcdGotoXY(1,3);							// 光标定位到闹钟小时的位置
				LcdPrintNum(Clock_Hour);		// 刷新显示改变后的闹钟小时
				LcdGotoXY(1,4);							// 定位光标到闹钟小时闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyClock_P==0)
			{
				break;
			}
		}
		
		LcdGotoXY(1,7);					// 定位光标到闹钟分钟的闪烁
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeyClock_P);			// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
		
		/* 调整分钟 */
		while(1)
		{
			if(KeyDown_P==0)							// 如果减按键被下去
			{
				if(Clock_Minute>0)					// 判断闹钟分钟是否大于0
					Clock_Minute--;						// 是的话就减去1
				LcdGotoXY(1,6);							// 光标定位到闹钟分钟的位置
				LcdPrintNum(Clock_Minute);	// 刷新显示改变后的闹钟分钟
				LcdGotoXY(1,7);							// 定位光标到闹钟分钟闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0)								// 如果加按键被下去
			{
				if(Clock_Minute<59)					// 判断闹钟分钟是否小于59
					Clock_Minute++;						// 是的话就加上1
				LcdGotoXY(1,6);							// 光标定位到闹钟分钟的位置
				LcdPrintNum(Clock_Minute);	// 刷新显示改变后的闹钟分钟
				LcdGotoXY(1,7);							// 定位光标到闹钟分钟闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyClock_P==0)
			{
				break;
			}
		}
		
		LcdGotoXY(1,12);				// 定位光标到闹钟开关的位置闪烁
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeyClock_P);			// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
		
		/* 闹钟开关 */
		while(1)
		{
			if(KeyDown_P==0)							// 如果减按键被下去
			{
				if(Clock_Swt==1)						// 判断闹钟是否开启
					Clock_Swt=0;							// 关闭闹钟
				LcdGotoXY(1,10);						// 光标定位到秒钟开关的位置
				LcdPrintStr("OFF");					// 液晶显示“OFF”
				LcdGotoXY(1,12);						// 定位光标到闹钟开关的位置闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyUp_P==0)									// 如果加按键被下去
			{
				if(Clock_Swt==0)						// 判断闹钟是否关闭
					Clock_Swt=1;							// 启动闹钟
				LcdGotoXY(1,10);						// 光标定位到秒钟开关的位置
				LcdPrintStr(" ON");					// 液晶显示“ ON”
				LcdGotoXY(1,12);						// 定位光标到闹钟开关的位置闪烁
				DelayMs(300);								// 延时0.3秒左右
			}
			
			if(KeyClock_P==0)
			{
				break;
			}
		}
		
		/* 退出前的设置 */
		LcdWriteCmd(0x0C);			// 关闭光标闪烁
		LcdShowInit();					// 液晶显示内容恢复为检测界面的
		DelayMs(10);						// 延时等待,消除按键按下的抖动
		while(!KeyClock_P);			// 等待按键释放
		DelayMs(10);						// 延时等待,消除按键松开的抖动
		Sector_Erase(0x2000);
		EEPROM_Write(0x2000,Clock_Hour);			// 往0x2000这个地址写入闹钟的小时 
		EEPROM_Write(0x2001,Clock_Minute);		// 往0x2001这个地址写入闹钟的分钟
		EEPROM_Write(0x2002,Clock_Swt);				// 往0x2002这个地址写入闹钟的开关
	}
}





/*********************************************************/
// 主函数
/*********************************************************/
void main()
{
	int temp;													// 保存温度值
	
	LcdInit();												// 执行液晶初始化	
	DS1302_Init();										// 时钟芯片的初始化
	LcdShowInit();										// 液晶显示内容的初始化

	if(DS1302_Read_Byte(0x81)>=128)		// 判断时钟芯片是否正在运行
	{
		DS1302_Write_Time();						// 如果没有,则初始化一个时间
	}
	

	Clock_Hour=EEPROM_Read(0x2000);		// 读取0x2000这个地址的内容,赋值给闹钟的小时变量
	if(Clock_Hour>23)									// 如果读取到的闹钟小时数值不正常,则重新赋值
	{
		Clock_Hour=12;
	}
  Clock_Minute=EEPROM_Read(0x2001);	// 读取0x2001这个地址的内容,赋值给闹钟的分钟变量
	if(Clock_Minute>59)								// 如果读取到的闹钟分钟数值不正常,则重新赋值
	{
		Clock_Minute=30;
	}
	Clock_Swt=EEPROM_Read(0x2002);		// 读取0x2002这个地址的内容,赋值给闹钟的开关变量
	if(Clock_Swt>1)										// 如果读取到的闹钟开关数值不正常,则重新赋值
	{
		Clock_Swt=0;
	}
	
	while(DS18B20_ReadTemp()==850)		// 等待温度传感器初始化完成
	{
		DelayMs(10);
	}
	
	while(1)
	{
		DS1302_Read_Time();				// 获取当前时钟芯片的时间,存在数组time_buf中
		FlashTime();							// 刷新时间显示
		ClockJudge();							// 闹钟工作的判断
		
		temp=DS18B20_ReadTemp();	// 读取温度
		LcdGotoXY(1,9);						// 定位到显示温度的地方
		LcdPrintTemp(temp);				// 显示温度

		KeyScanf1();							// 按键扫描(时间的设置)
		KeyScanf2();							// 按键扫描(闹钟的设置)
		
		DelayMs(100);							// 延时0.1秒
	}
}

设计文件:

链接:https://pan.baidu.com/s/1HDqd1U6U1ZvB2VO-UNJ9ig?pwd=7pad

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值