【51单片机】温度控制电机+多功能闹钟(综合设计报告+源代码+流程图+讲解)

1 设计目标

通过2046芯片获取温度,测量温度,控制风扇(电机)转速,温度高,转速快,温度低,转速慢,并有高温报警功能(蜂鸣器)。利用LCD1602模块、1032时钟模块和独立按键实现时钟显示控制。

2 主要功能

(1)实现时钟显示(年月日星期时分秒),并通过独立按键实现时间调节。

(2)实现温度测量并显示,温度控制直流电机转速,温度越高转速越快,当温度大于等于30°C时,实现蜂鸣器报警。

(3)实现闹钟设定并到时间提示,在时钟显示界面可调节闹钟开关。

(4)实现在不影响时钟计时情况下秒表计时。

3 硬件设计

 

 

 

 

 1602芯片标准字库表

1302时钟芯片时序图

1302时钟芯片寄存器2046AD转换时序图

LCD1602模块

独立按键模块

K5模式键 P1^4

K6增加键 P1^5

K7减少键 P1^6

K8 设置OK键 P1^7

DS1302时钟模块

1302时钟线SCLK=P1^0;

1302数据线IO=P1^1;

1302复位线RST=P1^2

xpt2046AD转换

输入DIN=P3^4

片选CS=P3^5

时钟DCLK=P3^6

输出DOUT=P3^7

蜂鸣器:P3^0

直流电机:P3^1=IN1

01与5V接在直流电机两端

4 软件流程

 

 

5 源代码

#include"REGx52.h"
#include"RICHMCU.H"
sbit XPY2046_DIN=P3^4;
sbit XPY2046_CS=P3^5;
sbit XPY2046_DCLK=P3^6;
sbit XPY2046_DOUT=P3^7;
sbit a0 = P0^0;
sbit a1 = P0^1;
sbit a2 = P0^2;
sbit a3 = P0^3;
sbit a4 = P0^4;
sbit a5 = P0^5;
sbit a6 = P0^6;
sbit a7 = P0^7;
sbit moto=P3^1;
sbit speaker = P3^0 ;	//蜂鸣器
sbit MODE = P1^4 ;	//模式键
sbit INC = P1^5 ;	//增加键
sbit DEC = P1^6 ;	//减少键
sbit OK = P1^7 ;	//OK键
#define LCD1602_DATA P0	//8位数据并行口
#define LCD1602_RS P2_6	//指令OR数据寄存器选择
#define LCD1602_RW P2_5	//读写控制
#define LCD1602_EN P2_7	//使能控制
#define LCD1602_CLR 0x01	//清屏
#define LCD1602_MODE 0x38	//8位数据,双列显示,5*7字形
#define LCD1602_ON 0x0c	//开显示,关光标,光标不闪烁
#define LCD1602_ADDR_MODE 0x06		//地址递增移光标 
#define DS1302_SCLK P1_0	//1302时钟线	
#define DS1302_IO P1_1		//1302数据线
#define DS1302_RST P1_2		//1302复位线

volatile uint8 data timedata[7] ;	//时间值
volatile uint8 data display_buffer1[16];	//显示缓冲区1 
volatile uint8 data display_buffer2[16];	//显示缓冲区2
volatile uint8 data temdata[5] ;	//存放温度值
volatile uint16 data tdat ;	//温度值变量
volatile uint8 data tflag ;	//温度正负值标志
volatile int8 self_pos = 0 ;//自定义三角形标志显示位置变量
volatile uint8 OK_VALUE = 0 ; //OK键键值变量 
volatile bit bdata DIS_ON = 1 ; //显示开关位 1 == on 0 == off
volatile bit bdata SCAN_ON = 0 ; //按键扫描开关位,由定时器每20MS刷新
volatile data MODE_ON = 0 ; //模式键按下后显示菜单的开关位
volatile data INC_VALUE = 0 ;
volatile data DEC_VALUE = 0 ;
volatile bit bdata ALARM_VALUE = 0 ;//闹钟标志位 
volatile bit bdata ALARM_ON = 1 ; //闹钟响时关闭标志位
volatile uint8 data read_1 = 1,read_2 = 1,read_3 = 1,read_4 = 1;
volatile uint8 data stopwatch_count = 0;
volatile uint8 data stopwatch_second = 0;
volatile uint8 data stopwatch_minute  = 0;
uint8 code self_table1[]={
						0x08,0x0f,0x12,0x0f,0x0a,0x1f,0x02,0x02,//	年
						0x1f,0x11,0x1f,0x11,0x1f,0x11,0x15,0x17,//月
						0x00,0x1f,0x11,0x1f,0x11,0x11,0x1f,0x00,//	日
						0x01,0x0c,0x17,0x14,0x17,0x0c,0x01,0x00,//闹钟标志
						0x10,0x18,0x1c,0x1e,0x1f,0x1c,0x18,0x10	};//三角形符号								


/**********************************************************
蜂鸣器
************************************************************/
void delay_ms(uint16 count)        // 延时时间count*1ms
{	uint16 i;
	for(;count>0;count--)
	{
		for(i=0;i<110;i++)
		{
			nop;
		}
	}
}
void speakers(uint8 speak_count)  //发声
{
	for(;speak_count>0;speak_count--)
		{
			speaker = 0 ;
			delay_ms(1) ;
			speaker = 1 ;
			delay_ms(3) ;
		}
}
/***********************************************************
忙检测
************************************************************/
 void LCD1602_check_busy(void)
{
	LCD1602_DATA = 0xff;
	LCD1602_RS = 0 ;	   //指令
	LCD1602_RW = 1 ;		//读
	LCD1602_EN = 1 ;		//上升沿写入
	while(LCD1602_DATA & 0x80) ;//首位为0方能运行
	LCD1602_EN = 0 ;			
}

/**********************************************************
写指令
************************************************************/

 void LCD1602_write_cmd(uint8 cmd)
{
	LCD1602_check_busy();	
	LCD1602_RS = 0 ;	//指令
	LCD1602_RW = 0 ;	 //写
	LCD1602_DATA = cmd ;	
	LCD1602_EN = 1 ;	 //上升沿写入
	LCD1602_EN = 0 ;
}

/***********************************************************
写数据
*************************************************************/
 void LCD1602_write_data(uint8 dat)
{
	LCD1602_check_busy();	
	LCD1602_RS = 1 ;     //数据	
	LCD1602_RW = 0 ;	 //写
	LCD1602_DATA = dat ;	
	LCD1602_EN = 1 ;	
	LCD1602_EN = 0 ;
}


/***********************************************************
1602初始化
************************************************************/
 void LCD1602_init(void)
{
	uint8 i  ;
	LCD1602_write_cmd(0x40);//CGRAM起始地址
	for(i=0;i<40;i++)
		LCD1602_write_data(self_table1[i]);//写入自定义字符
	LCD1602_write_cmd(LCD1602_MODE) ; //8位数据,双列显示,5*7字形
	LCD1602_write_cmd(LCD1602_ON) ;	  //开显示,关光标,光标不闪烁
	LCD1602_write_cmd(LCD1602_ADDR_MODE) ; //地址递增
	LCD1602_write_cmd(LCD1602_CLR) ;//清屏
}

/************************************************************
设置显示坐标
************************************************************/
 void LCD1602_set_postion(uint8 x , uint8 y)
{
	if(y<2)//行数大于2不执行
		{
			y &= 0x01 ;	//y值限定在0~1之间
			x &= 0x0f ;	//x值限定在0~15之间
			if(y == 0)
				x |= 0x40 ;	//如果显示是在第二行,则x的值加0x40
			x |= 0x80 ;		//获得x的值
			LCD1602_write_cmd(x) ;//写入坐标值到LCD
		}
}

/************************************************************
指定位置写字符
*************************************************************/
 void LCD1602_write_char(uint8 x , uint8 y , uint8 chardata)
{
	LCD1602_set_postion(x,y) ;
	LCD1602_write_data(chardata) ;
}

/************************************************************
指定位置写字符串
*************************************************************/
 void LCD1602_write_string(uint8 x , uint8 y , uint8 *string)
{
	LCD1602_set_postion(x,y) ;
	while((*string) != '\0')  //字符串结束时停止
	{	
		LCD1602_write_data(*string) ;
		string++ ;
	}
}
/****************************************************************
底层驱动函数(输入)
*****************************************************************/
 void DS1302_input(uint8 inputdata)
{
 unsigned char i = 0;		 
 for(i=0;i<8;i++)   
 {
  DS1302_IO = inputdata & 0x01; //开始传输低位 
  inputdata = inputdata >> 1;//右移一位
  DS1302_SCLK  = 1;      //拉高时钟表示已经发送
  DS1302_SCLK  = 0;      //拉低时钟准备继续放新的数据位
 } 
}	

/****************************************************************
底层驱动函数(输出)控制位的第七位必须为1
*****************************************************************/
 uint8 DS1302_output(void)
{	unsigned char i,dat;
	       
	for(i=0;i<8;i++)   //连续读8个二进制位数据
	 {
	   dat>>=1;       //将dat的各数据位右移1位,因为先读出的是字节的最低位
		if(DS1302_IO==1)    //如果读出的数据是1
		 dat|=0x80;    //将1取出,写在dat的最高位
		 DS1302_SCLK=1;       //将SCLK置于高电平,为下降沿读出
		 
		 DS1302_SCLK=0;       //拉低SCLK,形成脉冲下降沿
		 
	  }	 
  return (dat);        //将读出的数据返回
}

/****************************************************************
底层驱动函数(指定地址写一个字节的数据)
*****************************************************************/
 void DS1302_write_byte(uint8 cmd , uint8 dat)
{
	DS1302_SCLK = 0 ;		  //对应时序图
	DS1302_RST = 0 ;
	DS1302_RST = 1 ;
	DS1302_input(cmd) ;
	DS1302_input(dat) ;
	DS1302_RST = 0 ;
	DS1302_SCLK = 1 ;
}

/****************************************************************
底层驱动函数(指定地址读取一字节的数据)
*****************************************************************/
 uint8 DS1302_read_byte(uint8 cmd)
{
	uint8 receivedata = 0 ;
	DS1302_SCLK = 0 ;
	DS1302_RST = 0 ;
	DS1302_RST = 1 ;
	DS1302_input(cmd) ;
	receivedata = DS1302_output() ;
	DS1302_RST = 0 ;
	DS1302_SCLK = 1 ;
	return(receivedata) ;
}

/********************************************************
设置1302的初始时间
*********************************************************/
 void DS1302_init()
{	
			DS1302_write_byte(0x8e,0x00) ;//允许写操作 关闭写保护
			DS1302_write_byte(0x8c,0x22) ;//年
			DS1302_write_byte(0x8a,0x02) ;//星期
			DS1302_write_byte(0x88,0x04) ;//月
			DS1302_write_byte(0x86,0x25) ;//日
			DS1302_write_byte(0x84,0x10) ;//时
			DS1302_write_byte(0x82,0x00) ;//分
			DS1302_write_byte(0x80,0x00) ;//秒
			DS1302_write_byte(0x8e,0x80) ;//禁止写操作  打开写保护	 
	
}

/********************************************************
读取时间数据并放在timedata[]中
*********************************************************/
 void DS1302_read_time()
{
	timedata[0] = DS1302_read_byte(0x8d) ;	//年
	timedata[1] = DS1302_read_byte(0x89) ;	//月
	timedata[2] = DS1302_read_byte(0x87) ;	//日
	timedata[3] = DS1302_read_byte(0x85) ;	//时
	timedata[4] = DS1302_read_byte(0x83) ;	//分
	timedata[5] = DS1302_read_byte(0x81) ;	//秒
	timedata[6] = DS1302_read_byte(0x8b) ;	//星期
}


/***********************************************************
2046ad转换相关函数	   输出温控值
*************************************************************/

 unsigned int XPT2046_ReadAD(unsigned char Command)
{
	unsigned char i;
	unsigned int Data=0;
	XPY2046_DCLK=0;
	XPY2046_CS=0;
	for(i=0;i<8;i++)
	{
		XPY2046_DIN=Command&(0x80>>i);
		XPY2046_DCLK=1;
		XPY2046_DCLK=0;
	}
	for(i=0;i<16;i++)
	{
		XPY2046_DCLK=1;
		XPY2046_DCLK=0;
		if(XPY2046_DOUT){Data|=(0x8000>>i);}
	}	tflag==0;
	XPY2046_CS=1;
	return Data>>8;
}

//***********************************************//



void tem_conv()			//温度转换
			{	
				uint8 flagdat ;//定义温度值符号
				tdat=(tdat-108)/2+15;
				if(tdat>=30)speakers(2000)  ;//温度超过30°C报警
				
				if(tflag==0)
				temdata[4]=flagdat=0x20;//温度为正不显示符号
				   else
				 temdata[4]=flagdat=0x2d;//负温度显示负号:-
				 moto=0;
delay_ms(100-((tdat-23)*6));//通过温度来控制直流电机的转速
moto=1;
delay_ms((tdat-23)*6);	
				 	   temdata[0]=tdat/10+0x30;//温度十位
			     temdata[1]=tdat%10+0x30;//温度个位
			     temdata[2]=tdat*10%10+0x30;//小数十位
			     temdata[3]=tdat*100%10+0x30;//小数百位
				
			  }
			
/**************************************************************
更新显示缓冲区
***************************************************************/
 void updata_buffer(void)
{
	display_buffer1[0] = '2' ;
	display_buffer1[1] = '0' ;
	display_buffer1[2] = timedata[0]/16+0x30 ;	 //年
	display_buffer1[3] = timedata[0]%16+0x30 ;
	display_buffer1[4] = '.' ;
	display_buffer1[5] = timedata[1]/16+0x30 ;	//月
	display_buffer1[6] = timedata[1]%16+0x30 ;
	display_buffer1[7] = '.' ;
	display_buffer1[8] = timedata[2]/16+0x30 ;	 //日
	display_buffer1[9] = timedata[2]%16+0x30 ;
	display_buffer1[10] = ' ' ;
	
	display_buffer1[11] = ' ' ;
	switch(timedata[6]%16)	//星期
		{
			case 1 : {display_buffer1[12] = 'M' ; 
					display_buffer1[13] = 'o' ;
					display_buffer1[14] = 'n' ;	}break ;
			case 2 : {display_buffer1[12] = 'T' ; 
					display_buffer1[13] = 'u' ;
					display_buffer1[14] = 'e' ;	}break ;
			case 3 : {display_buffer1[12] = 'W' ; 
					display_buffer1[13] = 'e' ;
					display_buffer1[14] = 'd' ;	}break ;
			case 4 : {display_buffer1[12] = 'T' ; 
					display_buffer1[13] = 'h' ;
					display_buffer1[14] = 'u' ;	}break ;
			case 5 : {display_buffer1[12] = 'F' ; 
					display_buffer1[13] = 'r' ;
					display_buffer1[14] = 'i' ;	}break ;
			case 6 : {display_buffer1[12] = 'S' ; 
					display_buffer1[13] = 'a' ;
					display_buffer1[14] = 't' ;	}break ;
			case 7 : {display_buffer1[12] = 'S' ; 
					display_buffer1[13] = 'u' ;
					display_buffer1[14] = 'n' ;	}break ;
			default : break;
		}
	if(ALARM_VALUE == 1)
		display_buffer1[15] = 3 ;	   //闹钟标志
	else
		display_buffer1[15] = ' ' ;
	display_buffer2[0] = timedata[3]/16+0x30 ;	 //小时
	display_buffer2[1] = timedata[3]%16+0x30 ;
	display_buffer2[2] = ':' ;
	display_buffer2[3] = timedata[4]/16+0x30 ;	   //分钟
	display_buffer2[4] = timedata[4]%16+0x30 ;
	display_buffer2[5] = ':' ;
	display_buffer2[6] = timedata[5]/16+0x30 ;	//	秒
	display_buffer2[7] = timedata[5]%16+0x30 ;
	display_buffer2[8] = temdata[4] ;
	display_buffer2[9] = temdata[0] ;		 //温度
	display_buffer2[10] = temdata[1] ;
	display_buffer2[11] = '.' ;
	display_buffer2[12] = temdata[2] ;
	display_buffer2[13] = temdata[3] ;
	display_buffer2[14] = 0xdf ;
	display_buffer2[15] = 'C' ;
}

/******************************************************************
显示缓冲区内容
*******************************************************************/
 void display_buffer(void)
{
	uint8 i ;
	LCD1602_write_cmd(0x80) ;
	for(i=0;i<16;i++)
	LCD1602_write_data(display_buffer1[i]);
	LCD1602_write_cmd(0xc0) ;
	for(i=0;i<16;i++)
	LCD1602_write_data(display_buffer2[i]);
}
/*****************************************************************
按键扫描函数
******************************************************************/

void key_scan(void)
{
	if(MODE == 0)
		{
			delay_ms(20) ;
			while(!MODE) ;
			speakers(5) ; //消抖
			DIS_ON = 0 ;
			MODE_ON ++ ; //菜单开
			if(MODE_ON == 1 && OK_VALUE == 0)
			LCD1602_write_cmd(0x01) ;	 //清屏
			if(MODE_ON == 2 && OK_VALUE == 0)//未点确定点两下模式返回主页面
				{
					MODE_ON = 0 ;
					DIS_ON = 1 ;
					self_pos = 0 ;
				}
		}
	
	if(INC == 0 && MODE_ON == 1 && OK_VALUE == 0)	 //按菜单后按增加键
		{
			delay_ms(20) ; 
			while(!INC) ;
			speakers(5) ;
			LCD1602_write_cmd(0x01) ;
			self_pos++ ;
			if(self_pos > 2) //从3到1
			self_pos = 0 ;
		}
	if(DEC == 0 && MODE_ON == 1 && OK_VALUE == 0)	//按菜单后按减小键
		{
			delay_ms(20) ;
			while(!DEC) ;
			speakers(5) ;
			LCD1602_write_cmd(0x01) ;
			self_pos-- ;
			if(self_pos < -3)
			self_pos = -1 ;	 //从1到3
		}
	if(DEC == 0 )
		{
			delay_ms(20) ;
			while(!DEC) ;
			speakers(5) ;
			DEC_VALUE++;
		}
	if(INC == 0)
		{
			delay_ms(20) ;
			while(!INC) ;
			speakers(5) ;
			INC_VALUE++;
		}
	if(OK == 0 && MODE_ON != 0)
		{
			delay_ms(20) ;
			while(!OK) ;
			speakers(5) ;
			LCD1602_write_cmd(0x01) ;
			OK_VALUE++;
			INC_VALUE = 0 ;
			DEC_VALUE = 0 ;
		}
	if(OK == 0 && MODE_ON == 0)	  //闹钟开关
		{
			delay_ms(20) ;
			while(!OK) ;
			speakers(5) ;
			ALARM_ON = 1 ;
			if(ALARM_VALUE == 1)
				ALARM_VALUE = 0 ;
			else
				ALARM_VALUE = 1 ;
		}	
}
/*******************************************************************
按键菜单人机交互函数(第一级)
********************************************************************/
void menu_display_1()  //显示菜单
{
	if(MODE_ON == 1 && OK_VALUE == 0)
		{
			switch(self_pos)
				{	
					case -3 : {
								LCD1602_write_char(0,1,4) ;
								LCD1602_write_string(1,1,"1 Time setting ") ;
								LCD1602_write_string(1,0,"2 Alarm setting") ;
							  }break;
					case -2 : {
								LCD1602_write_char(0,0,4) ;
								LCD1602_write_string(1,1,"1 Time setting ") ;
								LCD1602_write_string(1,0,"2 Alarm setting") ;
							  }break;
					case -1 : {
								LCD1602_write_char(0,0,4) ;
								LCD1602_write_string(1,1,"2 Alarm setting ") ;
								LCD1602_write_string(1,0,"3 Stopwatch") ;
							  }break;
					case 0 :  {
								LCD1602_write_char(0,1,4) ;
								LCD1602_write_string(1,1,"1 Time setting ") ;
								LCD1602_write_string(1,0,"2 Alarm setting") ;
							  }break ;
					case 1 :  {
								LCD1602_write_char(0,0,4) ;
								LCD1602_write_string(1,1,"1 Time setting ") ;
							 	LCD1602_write_string(1,0,"2 Alarm setting") ;
							  }break ;
					case 2 :  {
								LCD1602_write_char(0,0,4) ;
								LCD1602_write_string(1,1,"2 Alarm setting ") ;
								LCD1602_write_string(1,0,"3 Stopwatch") ;
							  }break ;
					default :  break ;
				}	
		}
}

/*******************************************************************
按键菜单人机交互函数(第二级)
********************************************************************/
void menu_display_2(void)
{
	uint8 i ,j;
	if(MODE_ON != 0 && OK_VALUE != 0)  //按下模式并按下确定
		{
			LCD1602_write_cmd(0x0f) ;  //开显示,开光标,光标闪烁
			if(self_pos == 0 || self_pos == -3)//对应时钟调节
				{
					
					LCD1602_write_cmd(0x81) ;//设定DDRAM地址
					for(i=0;i<15;i++)
						LCD1602_write_data(display_buffer1[i]) ;
					LCD1602_write_cmd(0xc4) ;  //设定DDRAM地址
					for(j=0;j<8;j++)
						LCD1602_write_data(display_buffer2[j]) ;
					if(MODE_ON == 1) //调节年
						{
							uint8 item ;
							LCD1602_write_cmd(0x84) ;
							if(INC_VALUE !=0 )
								{
									item = DS1302_read_byte(0x8d) ;//获取实时值
									item=(item/16)*10+item%16;
									item++;
									if(item==100)item=0;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0x8c,item);
									INC_VALUE = 0 ;
								}
							if(DEC_VALUE != 0)
								{
									item = DS1302_read_byte(0x8d) ;
									item=(item/16)*10+item%16;
									item--;
									if(item < 0)item=99;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0x8c,item);
									DEC_VALUE = 0 ;
								}
						}
					else if(MODE_ON == 2)  //调节月
							{
								uint8 item ;
								LCD1602_write_cmd(0x87) ;
								if(INC_VALUE !=0 )
									{
										item = DS1302_read_byte(0x89) ;//获取实时值
										item=(item/16)*10+item%16;
										item++;
										if(item==13)item=1;
										item=(item/10)*16+item%10;
										DS1302_write_byte(0x8e,0x00);//允许写操作
										DS1302_write_byte(0x88,item);
										INC_VALUE = 0 ;
									}
								if(DEC_VALUE != 0)
									{
										item = DS1302_read_byte(0x89) ;
										item=(item/16)*10+item%16;
										item--;
										if(item == 0)item=12;
										item=(item/10)*16+item%10;
										DS1302_write_byte(0x8e,0x00);//允许写操作
										DS1302_write_byte(0x88,item);
										DEC_VALUE = 0 ;
									}
								}
					
					else if(MODE_ON == 3)	   //调节日
						{
							uint8 item ;
							LCD1602_write_cmd(0x8a) ;
							if(INC_VALUE !=0 )
								{
									item = DS1302_read_byte(0x87) ;
									item=(item/16)*10+item%16;
									item++;
									if(item==32)item=1;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0x86,item);
									INC_VALUE = 0 ;
								}
							if(DEC_VALUE != 0)
								{
									item = DS1302_read_byte(0x87) ;
									item=(item/16)*10+item%16;
									item--;
									if(item == 0)item=31;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0x86,item);
									DEC_VALUE = 0 ;
								}
						}
					
					else if(MODE_ON == 4)				//调节周
						{
							uint8 item ;
							LCD1602_write_cmd(0x8f) ;
							if(INC_VALUE !=0 )
								{
									item = DS1302_read_byte(0x8b) ;
									item=(item/16)*10+item%16;
									item++;
									if(item==8)item=1;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0x8a,item);
									INC_VALUE = 0 ;
								}
							if(DEC_VALUE != 0)
								{
									item = DS1302_read_byte(0x8b) ;
									item=(item/16)*10+item%16;
									item--;
									if(item == 0)item=7;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0x8a,item);
									DEC_VALUE = 0 ;
								}	
						}	
					else if(MODE_ON == 5)	  //调节小时
						{
							uint8 item ;
							LCD1602_write_cmd(0xc5) ;
							if(INC_VALUE !=0 )
								{
									item = DS1302_read_byte(0x85) ;
									item=(item/16)*10+item%16;
									item++;
									if(item==24)item=0;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0x84,item);
									INC_VALUE = 0 ;
								}
							if(DEC_VALUE != 0)
								{
									item = DS1302_read_byte(0x85) ;
									item=(item/16)*10+item%16;
									item--;
									if(item == -1)item=23;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0x84,item);
									DEC_VALUE = 0 ;
								}
						}
						
					else if(MODE_ON == 6)		   //调节分钟
						{
							uint8 item ;
							LCD1602_write_cmd(0xc8) ;
							if(INC_VALUE !=0 )
								{
									item = DS1302_read_byte(0x83) ;
									item=(item/16)*10+item%16;
									item++;
									if(item==60)item=0;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0x82,item);
									INC_VALUE = 0 ;
								}
							if(DEC_VALUE != 0)
								{
									item = DS1302_read_byte(0x83) ;
									item=(item/16)*10+item%16;
									item--;
									if(item == -1)item=59;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0x82,item);
									DEC_VALUE = 0 ;
								}
						}
						
					else if(MODE_ON == 7)		  //调节秒
						{
							uint8 item ;
							LCD1602_write_cmd(0xcb) ;
							if(INC_VALUE !=0 )
								{
									item = DS1302_read_byte(0x81) ;
									item=(item/16)*10+item%16;
									item++;
									if(item==60)item=0;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0x80,item);
									INC_VALUE = 0 ;
								}
							if(DEC_VALUE != 0)
								{
									item = DS1302_read_byte(0x81) ;
									item=(item/16)*10+item%16;
									item--;
									if(item == -1)item=59;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0x80,item);
									DEC_VALUE = 0 ;
								}
						}
					else
						{
							LCD1602_write_cmd(0x86);
							MODE_ON = 1 ;
						}
								
					if(OK_VALUE == 2 ) //点两下确定键 返回主菜单
						{
							MODE_ON = 1 ;
							OK_VALUE = 0 ;
							LCD1602_write_cmd(0x01) ;//清屏
							LCD1602_write_cmd(0x0c) ; //开显示,关光标,光标不闪烁
						}
				}
			if(self_pos == 1 || self_pos == -2)		//闹钟设定
				{	//uint8 alarm_temp ;
					LCD1602_write_cmd(0x80);  //设定DDRAM地址
					LCD1602_write_string(0,1,"Alarm time ") ;
					LCD1602_write_data(DS1302_read_byte(0xc1)/16+0x30);	  //写数据到DDRAM中
					LCD1602_write_data(DS1302_read_byte(0xc1)%16+0x30);
					LCD1602_write_data(':');
					
					LCD1602_write_data(DS1302_read_byte(0xc3)/16+0x30);
					LCD1602_write_data(DS1302_read_byte(0xc3)%16+0x30);
					if(ALARM_VALUE == 1)
						LCD1602_write_string(2,0," ON") ; 
					else 
						LCD1602_write_string(2,0,"OFF") ;
					LCD1602_write_cmd(0xcb)	;
					LCD1602_write_data(DS1302_read_byte(0xc5)/16+0x30);
					LCD1602_write_data(DS1302_read_byte(0xc5)%16+0x30);
					LCD1602_write_data(':');
					LCD1602_write_data(DS1302_read_byte(0xc7)/16+0x30);
					LCD1602_write_data(DS1302_read_byte(0xc7)%16+0x30);
					LCD1602_write_cmd(0x8c) ;
					if(MODE_ON == 1)
						{
							uint8 item ;
							if(INC_VALUE !=0 )
								{
									item = DS1302_read_byte(0xc1) ;
									item=(item/16)*10+item%16;
									item++;
									if(item==24)item=0;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0xc0,item);
									INC_VALUE = 0 ;
								}
							if(DEC_VALUE != 0)
								{
									item = DS1302_read_byte(0xc1) ;
									item=(item/16)*10+item%16;
									item--;
									if(item == -1)item=23;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0xc0,item);
									DEC_VALUE = 0 ;
								}
						}
					else if(MODE_ON == 2)
						{
							uint8 item ;
							LCD1602_write_cmd(0x8f) ;
							if(INC_VALUE !=0 )
								{
									item = DS1302_read_byte(0xc3) ;
									item=(item/16)*10+item%16;
									item++;
									if(item==60)item=0;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0xc2,item);
									INC_VALUE = 0 ;
								}
							if(DEC_VALUE != 0)
								{
									item = DS1302_read_byte(0xc3) ;
									item=(item/16)*10+item%16;
									item--;
									if(item == -1)item=59;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0xc2,item);
									DEC_VALUE = 0 ;
								}
						}
					else if(MODE_ON == 3)
						{
							LCD1602_write_cmd(0xc4);
							if(INC_VALUE != 0 || DEC_VALUE !=0 )
								{
									INC_VALUE = 0 ;
									DEC_VALUE = 0 ;
									ALARM_VALUE^=1 ; //取反
								}
						}
					else if(MODE_ON == 4)
						{
							uint8 item ;
							LCD1602_write_cmd(0xcc) ;
							if(INC_VALUE !=0 )
								{
									item = DS1302_read_byte(0xc5) ;
									item=(item/16)*10+item%16;
									item++;
									if(item==24)item=0;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0xc4,item);
									INC_VALUE = 0 ;
								}
							if(DEC_VALUE != 0)
								{
									item = DS1302_read_byte(0xc5) ;
									item=(item/16)*10+item%16;
									item--;
									if(item == -1)item=23;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0xc4,item);
									DEC_VALUE = 0 ;
								}
						}
					else if(MODE_ON == 5)
						{
							uint8 item ;
							LCD1602_write_cmd(0xcf) ;
							if(INC_VALUE !=0 )
								{
									item = DS1302_read_byte(0xc7) ;
									item=(item/16)*10+item%16;
									item++;
									if(item==60)item=0;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0xc6,item);
									INC_VALUE = 0 ;
								}
							if(DEC_VALUE != 0)
								{
									item = DS1302_read_byte(0xc7) ;
									item=(item/16)*10+item%16;
									item--;
									if(item == -1)item=59;
									item=(item/10)*16+item%10;
									DS1302_write_byte(0x8e,0x00);//允许写操作
									DS1302_write_byte(0xc6,item);
									DEC_VALUE = 0 ;
								}
						}
					else
						{
							LCD1602_write_cmd(0x8c);
							MODE_ON = 1 ;
						}
					if(OK_VALUE == 2 )
						{
							MODE_ON = 1 ;
							OK_VALUE = 0 ;
							LCD1602_write_cmd(0x01) ;
							LCD1602_write_cmd(0x0c) ;
						}
				}
			if(self_pos == 2 || self_pos == -1)
				{
					
					if(DEC_VALUE != 0)
						{
							TR0 = 0;
							
							DEC_VALUE = 0 ;
						}
					
					if(INC_VALUE != 0 )
						{	
							TR0= 1 ;
							INC_VALUE = 0 ;
						}
					LCD1602_write_cmd(0x0c) ;
					LCD1602_write_string(4,1,"stopwatch") ;
         			LCD1602_write_char(5,0,stopwatch_minute/10+0x30) ;
					LCD1602_write_char(6,0,stopwatch_minute%10+0x30) ;
					LCD1602_write_char(7,0,':') ;
					LCD1602_write_char(8,0,stopwatch_second/10+0x30) ;
					LCD1602_write_char(9,0,stopwatch_second%10+0x30) ;
					LCD1602_write_char(10,0,':') ;
					LCD1602_write_char(11,0,stopwatch_count/10+0x30) ;
					LCD1602_write_char(12,0,stopwatch_count%10+0x30) ;
				
					
					if(OK_VALUE == 2 )
						{
							TR0 = 0 ;
							stopwatch_minute = 0;
							stopwatch_second = 0;
							stopwatch_count = 0;
						}
					if(OK_VALUE == 3)
						{
							TR0 = 0 ;
							MODE_ON = 1 ;
							OK_VALUE = 0 ;
							stopwatch_minute = 0;
							stopwatch_second = 0;
							stopwatch_count = 0;
							LCD1602_write_cmd(0x01) ;
						}
				}
		}
	
}
/***********************************************************
闹钟初始化
************************************************************/
void alarm_init(void)
{
	DS1302_write_byte(0x8e,0x00) ;//允许写操作

	DS1302_write_byte(0xc0,0x12) ;//第一个闹钟的时
	DS1302_write_byte(0xc2,0x00) ;//第一个闹钟的分
	DS1302_write_byte(0xc4,0x12) ;//第二个闹钟的时
	DS1302_write_byte(0xc6,0x00) ;//第二个闹钟的分
		
	DS1302_write_byte(0x8e,0x80) ;//禁止写操作		
}
/***********************************************************
检测闹钟是否到了定时时间
************************************************************/
void alarm_check(void)
{
	
	if(ALARM_VALUE ==1 && ALARM_ON == 1)
		{
			read_1 = DS1302_read_byte(0x85) ;
			read_1 ^= DS1302_read_byte(0xc1);//异或
			read_2 = DS1302_read_byte(0x83) ;
			read_2 ^= DS1302_read_byte(0xc3);
			read_3 = DS1302_read_byte(0x85) ;
			read_3 ^= DS1302_read_byte(0xc5);
			read_4 = DS1302_read_byte(0x83) ;
			read_4 ^= DS1302_read_byte(0xc7);
		}
	if((read_1 == 0) && (read_2 == 0) || (read_3 == 0) && (read_4 == 0))//到时间 
		{
			if(ALARM_VALUE == 1)
				{
					speakers(100) ;
					delay_ms(10);
					speakers(10);
					delay_ms(5);
					ALARM_ON = 0 ;
				}
		}
}
/***********************************************************
主函数
************************************************************/
void main(void)
{
	TMOD = 0x01 ; //设置计时器模式为模式1,即16位定时器模式
	TH0 = 0xd8 ; //采取定时10ms,中断100次,形成1s时间。T2计算初值X=65536-10000=55536=D8F0
	TL0 = 0xf0 ;
	EA = 1 ;//开启总中断使能
	ET0 = 1 ;//开启计时器0中断使能
	TR0 = 0 ;//启动计时器
	LCD1602_init() ;
	alarm_init() ;
	DS1302_init() ;
	speakers(20)  ;//蜂鸣器 
	while(1)
		{	
			
			key_scan() ;
			menu_display_1() ;	  //菜单显示检测
			menu_display_2() ;
			
				
					alarm_check();//读时间 
					DS1302_read_time();
					tdat=XPT2046_ReadAD(0xd4);	//温度读取
					tem_conv();				//温度转换
					updata_buffer();//数据缓存区,时间、时钟 
					if(DIS_ON == 1)		   //主菜单显示
						{
								
							display_buffer();
						}		
		}
}
void t0_server(void) interrupt 1 using 1//中断调秒表 
{
	TH0 = 0xd8 ;
	TL0 = 0xf0 ;
	stopwatch_count++ ;
	if(stopwatch_count == 100)
		{
			stopwatch_second++ ;
			stopwatch_count = 0 ;
		}
	if(stopwatch_second == 60)
		{
			stopwatch_second = 0 ;
			stopwatch_minute++ ;
		}
	if(stopwatch_minute == 60)
		{stopwatch_minute = 0 ;}
}

 6 结论

LCD1602、xpt2046和DS1302编程主要采用了模块化编程的思路,思路都是一样,在基本工作原理的基础上将各类功能封装成函数,通过芯片资料上的时序图和地址指令,用函数调用实现各类功能的组合,大大简化了程序复杂度和可读性,这一思想也可以推广到其他程序之中。

猜你喜欢

转载自blog.csdn.net/m0_57007304/article/details/131493731