用普中开发板做的51单片机的智能时钟具有闹钟功能

DS1302+DS18B20+LCD1602

a1. main.c

#include<reg52.h>
#include<key.h>
#include<LCD1602.h>
#include<DS1302.h>
#include<music.h>
#include<DS18B20.H>

#define normal 0//正常显示时钟界面
#define settime 1//设定时钟界面
#define setalarm 2//设定闹钟界面
#define displayalarm 3//显示闹钟界面
#define normal_12 4//显示十二小时制界面
#define caidan 5

unsigned char system=normal;//我一开始就把界面切换为正常显示时钟界面

extern unsigned char i,k;

extern unsigned int code song[3][300];

unsigned char code *week[8]={"NO ","Mon ","Tue ","Wed ","Thu ","Fri ","Sat ","Sun "};

unsigned char code *clockzifu[4]={"ON ","OFF ","REP ","NRE "};

struct Time timeset={0x18,0x01,0x16,0x14,0x30,0x50,0x03}; 

//第一个闹钟
//第二个闹钟
//第三个闹钟
//第四个闹钟
//第五个闹钟
struct alarmtime xdata clock[5]={{1,16,14,31,0,1,0,1},{1,8,14,32,3,0,0,0},{1,7,18,49,1,1,1,0},{0,0,0,0,0,0,1,0},{1,25,0,0,0,0,1,2}};

unsigned char alarmnum;//闹钟

unsigned char a;

unsigned char flag=0;

unsigned char xinghao=0;

unsigned char tentoBCD(unsigned char dat)//十进制转换为BCD码函数
{
	unsigned char dat1,dat2;
	dat1=dat/10;
	dat2=dat%10;
	dat2=dat2+dat1*16;
	return dat2;
}

unsigned char BCDtoten(unsigned char dat)//BCD码转为十进制函数
{
	unsigned char dat1,dat2;
	dat1=dat/16;
	dat2=dat%16;
	dat2=dat2+dat1*10;
	return dat2;
}

void DS18B20deal(int temp)//DS18B20数据处理函数 显示温度更新温度	 
{
    //先判断温度值是否大于0或小于0等于0
   	float tp;//保存的数据可能带小数  
	if(temp<0)//当温度值为负数
  	{
		LCD1602_writechar(9,1,0x2D);//ASCII码中的-符号
		temp=temp-1;//因为读取的温度是实际温度的补码,所以减1,再取反求出原码
		temp=~temp;//还原读取的数据
		tp=temp;//保存到变量里面
		temp=tp*0.0625*100+0.5;//强制转换成一个整形的数据.留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就算加上0.5,还是在小数点后面。	
  	}
 	else//当温度值为正数
  	{			
		LCD1602_writechar(9,1,0x20);//ASCII码中的空格
		tp=temp;//因为数据处理有小数点所以将温度赋给一个浮点型变量。如果温度是正的那么,那么正数的原码就是补码它本身
		temp=tp*0.0625*100+0.5;//留两个小数点就*100,+0.5是四舍五入,因为C语言浮点数转换为整型的时候把小数点。后面的数自动去掉,不管是否大于0.5,而+0.5之后大于0.5的就是进1了,小于0.5的就算加上0.5,还是在小数点后面。	
	}
	LCD1602_writechar(10,1,temp/10000+'0');//温度百位
	LCD1602_writechar(11,1,temp%10000/1000+'0');//温度十位
	LCD1602_writechar(12,1,temp%1000/100+'0');//温度个位
    LCD1602_writechar(13,1,0x2E);//ASCII码小数点
	LCD1602_writechar(14,1,temp%100/10+'0');//小数点后一位
	LCD1602_writechar(15,1,temp%10+'0');//小数点后两位
}

void updatetime()//更新时钟上的时间
{
	unsigned char time[9];//存储变量
	DS1302_gettime(&timeset);//读取时间
	time[0]=BCDtoten(timeset.hour)/10+'0';//小时的十位
	time[1]=BCDtoten(timeset.hour)%10+'0';//小时的个位
	time[2]=':';
	time[3]=BCDtoten(timeset.min)/10+'0';//分的十位
	time[4]=BCDtoten(timeset.min)%10+'0';//分的个位
	time[5]=':';
	time[6]=BCDtoten(timeset.sec)/10+'0';//秒的十位
	time[7]=BCDtoten(timeset.sec)%10+'0';//秒的个位
	time[8]='\0';//字符串结束标志

	LCD1602_writestr(0,1,time);//在LCD上面打印时间
}

void updatetime_12()//更新十二小时制界面的时间
{
	unsigned char time[9];
	DS1302_gettime(&timeset);//读取时间
	time[0]= BCDtoten(timeset.hour)%12/10+'0';//小时的十位 
	time[1]= BCDtoten(timeset.hour)%12%10+'0';//小时的个位
	time[2]=':';
	time[3]= BCDtoten(timeset.min)/10+'0';//分的十位
	time[4]= BCDtoten(timeset.min)%10+'0';//分的个位
	time[5]=':';
	time[6]= BCDtoten(timeset.sec)/10+'0';//秒的十位
	time[7]= BCDtoten(timeset.sec)%10+'0';//秒的个位
	time[8]='\0';//字符串结束标志					                                                                                                                                                                       
	LCD1602_writestr(3,1,"TIME:");//打印出TIME的字符串
	LCD1602_writestr(8,1,time);//在第二行第四列显示时间
	if(BCDtoten(timeset.hour)>12)//要是小时大于12时
	{
	  LCD1602_writestr(0,1,"PM");//则显示PM
	} 
	else//小时不大于12
	{
	  LCD1602_writestr(0,1,"AM");//则显示AM
	}  
}

void updatedate()//更新日历
{
	unsigned char date[12];
	date[0]= '2';
	date[1]= '0';
	date[2]= BCDtoten(timeset.year)/10%10+'0';//年的十位
	date[3]= BCDtoten(timeset.year)%10+'0';//年的个位
	date[4]='.';
	date[5]= BCDtoten(timeset.mon)/10+'0';//月的十位
	date[6]= BCDtoten(timeset.mon)%10+'0';//月的个位
	date[7]='.';
	date[8]= BCDtoten(timeset.day)/10+'0';//日的十位
	date[9]= BCDtoten(timeset.day)%10+'0';//日的个位
	date[10]='\0';
	LCD1602_writestr(0,0,date);//显示年月日
	LCD1602_writestr(11,0,week[timeset.week]);//显示星期
}

void updatealarm()//更新闹钟设定值
{
	unsigned char str0[14];
	unsigned char str1[2];

	str0[0]=alarmnum+'0';
	str0[1]=' ';
	str0[2]=clock[alarmnum].mon/10+'0';//月份十位
	str0[3]=clock[alarmnum].mon%10+'0';//月份个位
	str0[4]='-';
	str0[5]=clock[alarmnum].day/10+'0';//日期十位
	str0[6]=clock[alarmnum].day%10+'0';//日期个位
	str0[7]=' ';
	str0[8]=clock[alarmnum].hour/10+'0';//小时十位
	str0[9]=clock[alarmnum].hour%10+'0';//小时个位
	str0[10]=':';
	str0[11]=clock[alarmnum].min/10+'0';//分钟十位
	str0[12]=clock[alarmnum].min%10+'0';//分钟个位
	str0[13]='\0';

	LCD1602_writestr(0,1,str0);

	str1[0]=clock[alarmnum].music+'0';//铃声
	str1[1]='\0';

	LCD1602_writestr(0,0,"U");
	LCD1602_writestr(1,0,str1);//显示铃声
	LCD1602_writestr(3,0,clockzifu[clock[alarmnum].alarmre+2]);//显示重不重复
	LCD1602_writestr(7,0,week[clock[alarmnum].week]);//显示星期
	LCD1602_writestr(11,0,clockzifu[clock[alarmnum].alarmon]);//显示开关	
}

void anjian4();

void anjian1()
{
  if(system==normal)
  {
    system=caidan;
	xinghao=0;
	LCD1602_clear();
	LCD1602_writechar(0,0,'*');
	LCD1602_writestr(1,0,"12");
	LCD1602_writestr(1,1,"alarm");
	LCD1602_writestr(8,0,"setclock");
	LCD1602_writestr(8,1,"setalarm");
  }
  else if(system==caidan&&xinghao==0)
  {
    system=normal_12;//切换到12小时制
	LCD1602_clear();//清屏
	updatetime_12();//显示12小时制的时间
	updatedate();//显示日期
  }
  else if(system==caidan&&xinghao==1)
  {
    system=displayalarm;//切换到闹钟显示
    LCD1602_clear();//清屏
	updatealarm();//显示闹钟界面
  }
  else if(system==caidan&&xinghao==2)
  {
    system=settime;//进入设置时间界面
	LCD1602_clear();
	updatetime();//刷新时间
    updatedate();//刷新日期
    DS18B20deal(DS18B20readtemp());//DS18B20数据处理函数 同时输出温度
    flag=0;//光标索引设置到秒钟上
    anjian4();//显示光标位置
    LCD1602_openguangbiao();//LCD1602打开光标显示
  }
  else if(system==caidan&&xinghao==3)
  {
    system=setalarm;//进入设置闹钟
	LCD1602_clear();//清屏
	updatealarm();//显示闹钟界面
    flag=0;//光标索引设置到多闹钟选择处上
    anjian4();//显示光标位置
    LCD1602_openguangbiao();//LCD1602打开光标显示
  }
  else if(system==settime)
  {
    system=normal;//切换回正常显示时钟的界面,显示日历时钟、温度。
	DS1302_settime(&timeset);//把设定时间写入实时时钟
	LCD1602_closeguangbiao();//LCD1602关闭光标显示
    LCD1602_clear();//LCD1602清屏
    updatetime();//刷新时间
	updatedate();//立即刷新日期
	DS18B20deal(DS18B20readtemp());//DS18B20数据处理函数 显示温度
  }
  else if(system==setalarm)
  {
     system=displayalarm;//返回到闹钟显示
	 LCD1602_closeguangbiao();//LCD1602关闭光标显示
	 LCD1602_clear();//清屏
	 updatealarm();//刷新闹钟界面
  }
}

void anjian4()
{
  if(system==caidan)
  {
    system=normal;
	LCD1602_clear();//清屏
	updatetime();//显示时钟时间
	updatedate();//显示日期
	DS18B20deal(DS18B20readtemp());//DS18B20数据处理函数 
  }
  else if(system==normal_12)
  {
    system=normal;//返回时钟显示界面
	LCD1602_clear();//清屏
	updatetime();//显示时钟时间
	updatedate();//显示日期
	DS18B20deal(DS18B20readtemp());//DS18B20数据处理函数
  }
  else if(system==displayalarm)
  {
    system=caidan;
	xinghao=1;
	LCD1602_clear();
	LCD1602_writechar(0,1,'*');
	LCD1602_writestr(1,0,"12");
	LCD1602_writestr(1,1,"alarm");
	LCD1602_writestr(8,0,"setclock");
	LCD1602_writestr(8,1,"setalarm");
  }
  else if(system==settime)//当前系统状态位于设置时间时 定义光标的位置
  {
	switch(flag)//保存的设置位
     {
       case 0:LCD1602_setcur(7,1);flag=1;break;//定位于秒钟个位处
       case 1:LCD1602_setcur(4,1);flag=2;break;//定位于分钟处
       case 2:LCD1602_setcur(1,1);flag=3;break;//定位于小时处
       case 3:LCD1602_setcur(11,0);flag=4;break;//定位于星期处
       case 4:LCD1602_setcur(9,0);flag=5;break;//定位于日处
       case 5:LCD1602_setcur(6,0);flag=6;break;//定位于月处
       default:LCD1602_setcur(3,0);flag=0;break;//定位于年处
     }
  }
  else if(system==setalarm)//当前系统状态位于设置闹钟时 定义光标的位置
     {
        switch(flag)//保存的设置位
        {
            case 0:LCD1602_setcur(0,1);flag=1;break;//定位于多闹钟选择处
			case 1:LCD1602_setcur(3,1);flag=2;break;//定位于闹钟月份处
			case 2:LCD1602_setcur(6,1);flag=3;break;//定位于闹钟日处
			case 3:LCD1602_setcur(9,1);flag=4;break;//定位于闹钟分钟处
			case 4:LCD1602_setcur(12,1);flag=5;break;//定位于闹钟小时处
			case 5:LCD1602_setcur(1,0);flag=6;break;//定位于闹钟铃声选择处
			case 6:LCD1602_setcur(3,0);flag=7;break;//定位于闹钟重复与不重复选择处
			case 7:LCD1602_setcur(7,0);flag=8;break;//定位于闹钟星期选择处 
            default:LCD1602_setcur(11,0);flag=0;break;//定位于闹钟开关处
        }
     }
}

void zengjia()//增加
{
    if(system==caidan)
	{
	  if(xinghao==0)
	  {
	    LCD1602_clear();
	    LCD1602_writechar(0,1,'*');
	    LCD1602_writestr(1,0,"12");
	    LCD1602_writestr(1,1,"alarm");
	    LCD1602_writestr(8,0,"setclock");
	    LCD1602_writestr(8,1,"setalarm");
		xinghao=1; 
	  }
	  else if(xinghao==1)
	  {
	  	LCD1602_clear();
	    LCD1602_writechar(7,0,'*');
	    LCD1602_writestr(1,0,"12");
	    LCD1602_writestr(1,1,"alarm");
	    LCD1602_writestr(8,0,"setclock");
	    LCD1602_writestr(8,1,"setalarm");
		xinghao=2; 
	  }
	  else if(xinghao==2)
	  {
	    LCD1602_clear();
	    LCD1602_writechar(7,1,'*');
	    LCD1602_writestr(1,0,"12");
	    LCD1602_writestr(1,1,"alarm");
	    LCD1602_writestr(8,0,"setclock");
	    LCD1602_writestr(8,1,"setalarm");
		xinghao=3; 
	  }
	  else if(xinghao==3)
	  {
	    LCD1602_clear();
	    LCD1602_writechar(0,0,'*');
	    LCD1602_writestr(1,0,"12");
	    LCD1602_writestr(1,1,"alarm");
	    LCD1602_writestr(8,0,"setclock");
	    LCD1602_writestr(8,1,"setalarm");
		xinghao=0; 
	  }
	}
	else if(system==settime)//当设置日历时间的界面时
    {
		switch(flag)//检查光标位置
        {				
			case 1: a=BCDtoten(timeset.sec);//把BCD码转为十进制 因为DS1302里时钟程序读写时都是BCD码 转为10进制更好处理
					if(a<59)
					{
					  a++;
					}  
					else
					{
					  a=0;//限制设置秒钟不超过59秒,超过则回到0
					} 
					timeset.sec=tentoBCD(a);//把十进制转为BCD码 因为DS1302时钟程序读写时都是BCD码 将加完的东西重新赋值给sec
					LCD1602_writechar(6,1,(timeset.sec>>4)+'0');//秒的十位
					LCD1602_writechar(7,1,(timeset.sec&0x0f)+'0');//秒的个位
					LCD1602_setcur(7,1);//光标保持原位
					break;

			case 2:	a=BCDtoten(timeset.min);//把BCD码转为十进制
					if(a<59)
					{
					  a++;
					}  
					else
					{
					  a=0;//限制设置分钟不超过59分,超过则回到0
					} 
					timeset.min=tentoBCD(a);//把十进制转为BCD码
					LCD1602_writechar(3,1,(timeset.min>>4)+'0');//分的十位
					LCD1602_writechar(4,1,(timeset.min&0x0f)+'0');//分的个位
					LCD1602_setcur(4,1);//光标保持原位
					break;

			case 3:	a=BCDtoten(timeset.hour);//把BCD码转为十进制
					if(a<23)
					{
					  a++;
					}  
					else
					{
					  a=0;//限制设置小时不超过23时,超过则回到0
					} 
					timeset.hour=tentoBCD(a);//把十进制转为BCD码
					LCD1602_writechar(0,1,(timeset.hour>>4)+'0');//小时的十位
					LCD1602_writechar(1,1,(timeset.hour&0x0f)+'0');//小时的个位
					LCD1602_setcur(1,1);//光标保持原位
					break;

			case 4: if(timeset.week<7)//限制不超过星期日,如果超过则回到周一
					{
					  timeset.week++;
					}  
					else
					{
					  timeset.week=1;//回到星期一
					} 
					LCD1602_writestr(11,0,week[timeset.week]);//
					LCD1602_setcur(11,0);//光标保持原位
					break;

			case 5:	a=BCDtoten(timeset.day);//把BCD码转为十进制
					if(a<31)
					{
					  a++;
					}  
					else
					{
					  a=1;//限制设置日期不超过31日,超过则回到1
					} 
					timeset.day=tentoBCD(a);//把十进制转为BCD码
					LCD1602_writechar(8,0,(timeset.day>>4)+'0');//日的十位
					LCD1602_writechar(9,0,(timeset.day&0x0f)+'0');//日的个位
					LCD1602_setcur(9,0);//光标保持原位
					break;

			case 6:	a=BCDtoten(timeset.mon);//把BCD码转为十进制
					if(a<12)
					{
					  a++;
					}  
					else
					{
					  a=1;//限制设置月份不超过12月,超过则回到1
					}
					timeset.mon=tentoBCD(a);//把十进制转为BCD码
					LCD1602_writechar(5,0,(timeset.mon>>4)+'0');//月的十位
					LCD1602_writechar(6,0,(timeset.mon&0x0f)+'0');//月的个位
					LCD1602_setcur(6,0);//光标保持原位
					break;

			case 0:	a=BCDtoten(timeset.year);//把BCD码转为十进制
					if(a<99)
					{
					  a++;					  
					}  
					else
					{
					  a=0;//限制设置年不超过99年,超过则回到0
					} 
					timeset.year=tentoBCD(a);//把十进制转为BCD码
					LCD1602_writechar(2,0,(timeset.year>>4)+'0');//年的十位
					LCD1602_writechar(3,0,(timeset.year&0x0f)+'0');//年的个位
					LCD1602_setcur(3,0);//光标保持原位
					break;
		}	
	}
	else if(system==setalarm)//当设置闹钟的时候
	{
		switch(flag)//检查光标位置
        {
			case 1: if(alarmnum<4)//换闹钟
			        {
					  alarmnum++;
			        }  
					else
					{
					  alarmnum=0;
					} 
					updatealarm();//更新闹钟设定值
					LCD1602_setcur(0,1);//光标保持原位
					break;
			case 2:	if(clock[alarmnum].mon<12)
			        {
					  clock[alarmnum].mon++;
			        }  
					else
					{
					  clock[alarmnum].mon=1;//限制设置月份不超过12月,超过则回到1
					} 
					LCD1602_writechar(2,1,(clock[alarmnum].mon/10)+'0');//月的十位
					LCD1602_writechar(3,1,(clock[alarmnum].mon%10)+'0');//月的个位
					LCD1602_setcur(3,1);//光标保持原位
					break;
			case 3:	if(clock[alarmnum].day<31)
			        {
					  clock[alarmnum].day++;
					}  
					else
					{
					  clock[alarmnum].day=1;//限制设置日期不超过31日,超过则回到1
					} 
					LCD1602_writechar(5,1,(clock[alarmnum].day/10)+'0');//日的十位
					LCD1602_writechar(6,1,(clock[alarmnum].day%10)+'0');//日的个位
					LCD1602_setcur(6,1);//光标保持原位
					break;
			case 4:	if(clock[alarmnum].hour<23)
			        {
					  clock[alarmnum].hour++;
					} 
					else
					{
					  clock[alarmnum].hour=0;//限制设置小时不超过23时,超过则回到0
					} 											   																																				
					LCD1602_writechar(8,1,(clock[alarmnum].hour/10)+'0');//小时的十位
					LCD1602_writechar(9,1,(clock[alarmnum].hour%10)+'0');//小时的个位
					LCD1602_setcur(9,1);//光标保持原位
					break;
			case 5: if(clock[alarmnum].min<59)
			        {
					  clock[alarmnum].min++;
					}  
					else
					{
					  clock[alarmnum].min=0;//限制设置分钟不超过59分,超过则回到0
					} 
					LCD1602_writechar(11,1,(clock[alarmnum].min/10)+'0');//分钟的十位
					LCD1602_writechar(12,1,(clock[alarmnum].min%10)+'0');//分钟的个位
					LCD1602_setcur(12,1);//光标保持原位
					break;
					
			case 6:	if(clock[alarmnum].music<2)
			        {
					  clock[alarmnum].music++;
					}  
					else
					{
					  clock[alarmnum].music=0;
					} 
					LCD1602_writechar(1,0,clock[alarmnum].music+'0');//音乐曲目
					LCD1602_setcur(1,0);//光标保持原位
					break;
								
			case 7:	clock[alarmnum].alarmre=~clock[alarmnum].alarmre;//取反 
					LCD1602_writestr(3,0,clockzifu[clock[alarmnum].alarmre+2]);//显示闹钟状态 
					LCD1602_setcur(3,0);//光标保持原位
					break;
			case 8:	if(clock[alarmnum].week<7)
					{
					  clock[alarmnum].week++;
					}  
					else
					{
					  clock[alarmnum].week=0;//限制不超过星期日,如果超过则回到不设星期
					} 
					LCD1602_writestr(7,0,week[clock[alarmnum].week]);//显示到液晶上;
					LCD1602_setcur(7,0);//光标保持原位
					break;

			case 0: clock[alarmnum].alarmon=~clock[alarmnum].alarmon;//取反
					LCD1602_writestr(11,0,clockzifu[clock[alarmnum].alarmon]);//显示闹钟状态 
					LCD1602_setcur(11,0);//光标保持原位
					break;		
		}		
	}
}

void jianxiao()//S4按键功能函数,数据减
{
	if(system==caidan)
	{
	  if(xinghao==0)
	  {
	    LCD1602_clear();
	    LCD1602_writechar(7,1,'*');
	    LCD1602_writestr(1,0,"12");
	    LCD1602_writestr(1,1,"alarm");
	    LCD1602_writestr(8,0,"setclock");
	    LCD1602_writestr(8,1,"setalarm");
		xinghao=3; 
	  }
	  else if(xinghao==3)
	  {
	  	LCD1602_clear();
	    LCD1602_writechar(7,0,'*');
	    LCD1602_writestr(1,0,"12");
	    LCD1602_writestr(1,1,"alarm");
	    LCD1602_writestr(8,0,"setclock");
	    LCD1602_writestr(8,1,"setalarm");
		xinghao=2; 
	  }
	  else if(xinghao==2)
	  {
	    LCD1602_clear();
	    LCD1602_writechar(0,1,'*');
	    LCD1602_writestr(1,0,"12");
	    LCD1602_writestr(1,1,"alarm");
	    LCD1602_writestr(8,0,"setclock");
	    LCD1602_writestr(8,1,"setalarm");
		xinghao=1; 
	  }
	  else if(xinghao==1)
	  {
	    LCD1602_clear();
	    LCD1602_writechar(0,0,'*');
	    LCD1602_writestr(1,0,"12");
	    LCD1602_writestr(1,1,"alarm");
	    LCD1602_writestr(8,0,"setclock");
	    LCD1602_writestr(8,1,"setalarm");
		xinghao=0; 
	  }
	}
	else if(system==settime)//设置日期/时间
    {
		switch(flag)//检查光标位置
        {				
			case 1:	a=BCDtoten(timeset.sec);//把BCD码转为十进制
					if(a!=0)
					{
					  a--;
					}  
					else
					{
					  a=59;//限制设置秒钟不为0时减1,为0时回到59
					} 
					timeset.sec=tentoBCD(a);//把十进制转为BCD码
					LCD1602_writechar(6,1,(timeset.sec>>4)+'0');//秒的十位
					LCD1602_writechar(7,1,(timeset.sec&0x0f)+'0');//秒的个位
					LCD1602_setcur(7,1);//光标保持原位
					break;

			case 2:	a=BCDtoten(timeset.min);//把BCD码转为十进制
					if(a!=0)
					{
					  a--;
					}  
					else
					{
					  a=59;//限制设置分钟不为0时减1,为0时回到59
					} 
					timeset.min=tentoBCD(a);//把十进制转为BCD码
					LCD1602_writechar(3,1,(timeset.min>>4)+'0');//分的十位
					LCD1602_writechar(4,1,(timeset.min&0x0f)+'0');//分的个位
					LCD1602_setcur(4,1);//光标保持原位
					break;

			case 3:	a=BCDtoten(timeset.hour);//把BCD码转为十进制
					if(a!=0)
					{
					  a--;
					}  
					else 
					{
					  a=23;//限制设置小时不为0时减1,为0时回到23
					}
					timeset.hour=tentoBCD(a);//把十进制转为BCD码
					LCD1602_writechar(0,1,(timeset.hour>>4)+'0');//小时的十位
					LCD1602_writechar(1,1,(timeset.hour&0x0f)+'0');//小时的个位
					LCD1602_setcur(1,1);//光标保持原位
					break;

			case 4: //如果为当前为星期一时,回到星期天
					if(timeset.week!=1)
					{
					  timeset.week--;
					}  
					else
					{
					  timeset.week=7;
					} 
					LCD1602_writestr(11,0,week[timeset.week]);//显示到液晶上;
					LCD1602_setcur(11,0);//光标保持原位
					break;

			case 5:	a=BCDtoten(timeset.day);//把BCD码转为十进制
					if(a!=1)
					{
					  a--;
					}  
					else
					{
					  a=31;
					}//限制设置日期不为1时减1,为0时回到31 
					timeset.day=tentoBCD(a);//把十进制转为BCD码
					LCD1602_writechar(8,0,(timeset.day>>4)+'0');//日期的十位
					LCD1602_writechar(9,0,(timeset.day&0x0f)+'0');//日期的个位
					LCD1602_setcur(9,0);//光标保持原位
					break;

			case 6:	a=BCDtoten(timeset.mon);//把BCD码转为十进制
					if(a!=1)
					{
					  a--;
					}  
					else
					{
					  a=12;//限制设置月份不为1时减1,为0时回到12
					} 
					timeset.mon=tentoBCD(a);//把十进制转为BCD码
					LCD1602_writechar(5,0,(timeset.mon>>4)+'0');//月份的十位
					LCD1602_writechar(6,0,(timeset.mon&0x0f)+'0');//月份的个位
					LCD1602_setcur(6,0);//光标保持原位
					break;

			case 0:	a=BCDtoten(timeset.year);//把BCD码转为十进制
					if(a!=0)
					{
					  a--;
					}  
					else
					{
					  a=99;//限制设置年不为0时减1,为0时回到99
					} 
					timeset.year=tentoBCD(a);//把十进制转为BCD码
					LCD1602_writechar(2,0,(timeset.year>>4)+'0');//年的十位
					LCD1602_writechar(3,0,(timeset.year&0x0f)+'0');//年的个位
					LCD1602_setcur(3,0);//光标保持原位
					break;
		}		
	}
	else if(system==setalarm)//设置闹钟
	{
		switch(flag)//检查光标位置
        {
			case 1: if(alarmnum!=0)//换闹钟
			        {
					  alarmnum--;
					}
					else
					{
					  alarmnum=4;
					} 
					updatealarm();//刷新闹钟界面
					LCD1602_setcur(0,1);//光标保持原位
					break;
			case 2:	if(clock[alarmnum].mon!=1)
			        {
					  clock[alarmnum].mon--;
					}  
					else
					{
					  clock[alarmnum].mon=12;//限制设置月份不超过12月,超过则回到1
					}
					LCD1602_writechar(2,1,(clock[alarmnum].mon/10)+'0');//月份十位
					LCD1602_writechar(3,1,(clock[alarmnum].mon%10)+'0');//月份个位
					LCD1602_setcur(3,1);//光标保持原位
					break;
			case 3:	if(clock[alarmnum].day!=1)
			        {
					  clock[alarmnum].day--;
					}  
					else
					{
					  clock[alarmnum].day=31;//限制设置日期不超过31日,超过则回到1
					} 
					LCD1602_writechar(5,1,(clock[alarmnum].day/10)+'0');//日期十位
					LCD1602_writechar(6,1,(clock[alarmnum].day%10)+'0');//日期个位
					LCD1602_setcur(6,1);//光标保持原位
					break;
			case 4:	if(clock[alarmnum].hour!=0)
			        {
					  clock[alarmnum].hour--;
					}  
					else
					{
					  clock[alarmnum].hour=23;//限制设置小时不超过23时,超过则回到0
					} 											   																																				
					LCD1602_writechar(8,1,(clock[alarmnum].hour/10)+'0');//小时十位
					LCD1602_writechar(9,1,(clock[alarmnum].hour%10)+'0');//小时个位
					LCD1602_setcur(9,1);//光标保持原位
					break;
			case 5: if(clock[alarmnum].min!=0)
			        {
					  clock[alarmnum].min--;
					}  
					else
					{
					  clock[alarmnum].min=59;//限制设置分钟不超过59分,超过则回到0
					} 
					LCD1602_writechar(11,1,(clock[alarmnum].min/10)+'0');//分钟十位
					LCD1602_writechar(12,1,(clock[alarmnum].min%10)+'0');//分钟个位
					LCD1602_setcur(12,1);//光标保持原位
					break;
					
			case 6:	if(clock[alarmnum].music!=0)
			        {
					  clock[alarmnum].music--;
					}  
					else
					{
					  clock[alarmnum].music=2;
					} 
					LCD1602_writechar(1,0,clock[alarmnum].music+'0');
					LCD1602_setcur(1,0);//光标保持原位
					break;
								
			case 7:	clock[alarmnum].alarmre=~clock[alarmnum].alarmre;
					LCD1602_writestr(3,0,clockzifu[clock[alarmnum].alarmre+2]);//显示闹钟状态 
					LCD1602_setcur(3,0);//光标保持原位
					break;
			case 8:	if (clock[alarmnum].week!=0)
					{
					  clock[alarmnum].week--;
					}  
					else
					{
					  clock[alarmnum].week=7;
					} 
					LCD1602_writestr(7,0,week[clock[alarmnum].week]);//显示到液晶上;
					LCD1602_setcur(7,0);//光标保持原位
					break;

			case 0: clock[alarmnum].alarmon=~clock[alarmnum].alarmon;
					LCD1602_writestr(11,0,clockzifu[clock[alarmnum].alarmon]);//显示闹钟状态 
					LCD1602_setcur(11,0);//光标保持原位
					break;
		}		
	}
}

void alarmset()//闹钟函数
{
	unsigned char i;
	for(i=0;i<5;i++)//扫描闹钟
	{
	    //0就是重复 1不重复
		if(clock[i].alarmre)//不重复时
		{
		  	if((BCDtoten(timeset.hour)==clock[i].hour)&&(BCDtoten(timeset.min)==clock[i].min)&&(BCDtoten(timeset.mon)==clock[i].mon)&&(BCDtoten(timeset.day)==clock[i].day)&&(BCDtoten(timeset.sec))==0)//检查闹钟的时间和日期是否跟目前的时钟时间日期匹配
		    {
			      //0为打开 1为关闭
		          if(!clock[i].alarmon)//检查闹钟是否打开 
						{
						  LCD1602_clear();//清屏
						  LCD1602_writestr(0,0,"Alarm");
						  LCD1602_writechar(6,0,i+'0');
						  LCD1602_writestr(8,0,"ring!");
						  LCD1602_writestr(0,1,"Please press!");
						  playmusic(clock[i].music);//播放铃声
						  LCD1602_clear();//清屏
						}
		    }
		}
		else//如果重复
		{
			if(clock[i].week)//有设置星期 则是每一个特定星期重复
			{
				if(clock[i].week==timeset.week)//看闹钟设置的星期是否为现在的星期 
				{
					if((BCDtoten(timeset.hour)==clock[i].hour)&&(BCDtoten(timeset.min)==clock[i].min)&&(BCDtoten(timeset.sec))==0)//检查闹钟的时间是否跟目前的时钟时间匹配
				    {
				          if(!clock[i].alarmon)//检查闹钟是否打开
						{
						  LCD1602_clear();//清屏
						  LCD1602_writestr(0,0,"Alarm");
						  LCD1602_writechar(6,0,i+'0');
						  LCD1602_writestr(8,0,"ring!");
						   LCD1602_writestr(0,1,"Please press!");
						  playmusic(clock[i].music);//播放音乐
						  LCD1602_clear();//清屏
						}
				    }
					
				}	
			
			}
			else//没有设置星期且在重复的情况下 则为每天都响
			{
					if((BCDtoten(timeset.hour)==clock[i].hour)&&(BCDtoten(timeset.min)==clock[i].min)&&(BCDtoten(timeset.sec))==0)//检查闹钟的时间是否跟目前的时钟时间匹配
				    {
				        if (!clock[i].alarmon)//检查闹钟是否打开
						{
						  LCD1602_clear();//清屏
						  LCD1602_writestr(0,0,"Alarm");
						  LCD1602_writechar(6,0,i+'0');
						  LCD1602_writestr(8,0,"ring!");
						  LCD1602_writestr(0,1,"Please press!");
						  playmusic(clock[i].music);//播放音乐
						  LCD1602_clear();//清屏 
						}
				    }				
			}	
		}
	}	   
}


void dingshiqi0()
{
	TMOD|=0x01;
	TH0=0;
	TL0=0;
	TR0=0;
	ET0=1;
	PT0=1;
	EA=1;
}

void dingshiqi1()
{
	TMOD|=0x10;
	EA=1;
	ET1=1;
	TR1=1;
	TH1=0xED;
	TL1=0xFE;
}

void timer0() interrupt 1 
{	
    TH0=song[k][i]/256;
	TL0=song[k][i]%256;
	beep=~beep; 

}

void timer1() interrupt 3
{
    TH1=0xED;
	TL1=0xFE;
 	key_scan();		
}

void main()
{
	dingshiqi0();//定时器0初始化
	dingshiqi1();//定时器1初始化
	LCD1602_init();//LCD1602初始化
	DS1302_init();//DS1302初始化
	while(1)
	{
		key_driver();
		alarmset();//闹钟设定函数
		if(system==normal)//当状态为正常显示时间时
		{
		   updatetime();//刷新时间
		   updatedate();//刷新日期
		   DS18B20deal(DS18B20readtemp());//DS18B20数据处理函数 同时输出温度 
		}
		else if(system==normal_12)//当状态为显示12小时制
		{
		   updatetime_12();//刷新时间
		   updatedate();//刷新日期
		}
	}
}

a2. key.h

#ifndef _KEY_H
#define _KEY_H

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

//键盘位定义
sbit key1=P1^0;
sbit key2=P1^1;
sbit key3=P1^2;
sbit key4=P1^3;

extern void key_scan();//更新按键状态

extern void key_driver();//按键动作

extern void key_action(unsigned char keycode);//按键状态检测

extern void delayms(unsigned int a);//延时

#endif

b2. key.c

#include<key.h>

extern unsigned char start;

unsigned int keysta[4]={1};//设置按键默认初始状态 初始状态为没用被按下

unsigned int keygroup[4]={0x01,0x02,0x04,0x08};//0000 0001 0000 0010 0000 0010 0000 1000 定义四个按键哪个被按下

unsigned int keybackup[4]={1};//设置按键备份初始化

void delayms(unsigned int a)//延时1ms
{
	unsigned char i;
	for(;a>0;a--)
		for(i=0;i<144;i++);
}

void key_scan()//更新按键状态
{
	  unsigned char i;
	  for(i=0;i<4;i++)
	  {
	  	 if(!(P1&keygroup[i]))//如果某个按键被按下
		 {
		 	delayms(5);//延时5ms消抖
		 	if(!(P1&keygroup[i]))//重新检测是否真有某个按键按下
			{
				keysta[i]=0;//设置按键的状态是被按下
			}
		 }else keysta[i]=1;//按键没有被按下
	  }
}

void key_action(unsigned char keycode)//按键动作
{	start=0;
	switch(keycode)
	{
		case 0:anjian1();break;//第一个按键是切换界面
		case 1:zengjia();break;//S3按键功能函数,数据加
		case 2:jianxiao();break;//S4按键功能函数,数据减
		case 3:anjian4();break;//在相应的界面中进入更改界面
    }
}

void key_driver()//检测按键状态
{
   unsigned char i;
   for(i=0;i<4;i++)//扫描四个按键
   {
   	  if(keybackup[i]!=keysta[i])//如果四个按键其中有个跟原来的状态不一样
	  {
	  	if(keybackup[i])
		{
			key_action(i);//按键作出其对应的动作
		}
		keybackup[i]=keysta[i];//让当前的按键状态覆盖掉原来的按键状态
	  }
   }
}

a3. LCD1602.h

//1602液晶定义
#ifndef _LCD1602_H__
#define _LCD1602_H_

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

sbit LCD1602_RW=P2^5;//0-向LCD写入指令或数据 1-读取信息
sbit LCD1602_RS=P2^6;//选择指令还是数据 0-指令 1-数据
sbit LCD1602_EN=P2^7;//使能信号,下降沿时执行指令

extern void LCD1602_readok();//等待LCD1602空闲

extern void LCD1602_writecom(unsigned char cmd);//向LCD1602写入命令

extern void LCD1602_writedat(unsigned char dat);//向LCD1602写入数据

extern void LCD1602_setcur(unsigned int x,unsigned int y);//坐标定义

extern void LCD1602_clear();//清屏函数

extern void LCD1602_writechar(unsigned int x,unsigned int y,unsigned char i);//打印字符

extern void LCD1602_writestr(unsigned int x,unsigned int y,char *str);//打印字符串

extern void LCD1602_openguangbiao();//打开光标

extern void LCD1602_closeguangbiao();//关闭光标

extern void LCD1602_init();//LCD1602初始化

#endif

b3. LCD1602.c

#include <LCD1602.h>

void LCD1602_readok()//等待LCD1602空闲
{
	 unsigned char busy;
	 P0=0XFF;//初始化
	 LCD1602_RS=0;
	 LCD1602_RW=1;
	 do
	 {
	    LCD1602_EN=1;
		busy=P0;
		LCD1602_EN=0;
	 }while(busy&0X80);

}

void LCD1602_writecom(unsigned char cmd)//向LCD1602写入命令
{
	LCD1602_readok();
	LCD1602_RS=0;
	LCD1602_RW=0;
	P0=cmd;
	LCD1602_EN=1;
	LCD1602_EN=0;
	
}

void LCD1602_writedat(unsigned char dat)//向LCD1602写入数据
{
	LCD1602_readok();
	LCD1602_RS=1;
	LCD1602_RW=0;
	P0=dat;
	LCD1602_EN=1;
	LCD1602_EN=0;
}
void LCD1602_setcur(unsigned int x,unsigned int y)//坐标定位
{  
   if(y) x|=0x40;
   x|=0x80;
   LCD1602_writecom(x);
}
void LCD1602_clear()//清屏函数
{
   LCD1602_writecom(0x01);
}
void LCD1602_writechar(unsigned int x,unsigned int y,unsigned char i)//打印字符
{
   LCD1602_setcur(x,y);
   LCD1602_writedat(i);
}
void LCD1602_writestr(unsigned int x,unsigned int y,char *str)//打印字符串
{
   LCD1602_setcur(x,y);
   while(*str!='\0')
      LCD1602_writedat(*str++);
}
void LCD1602_openguangbiao()//打开光标
{
	LCD1602_writecom(0x0F);//屏幕开、光标开、闪烁关
}
void LCD1602_closeguangbiao()//关闭光标
{
	LCD1602_writecom(0x0C);//屏幕开、光标关、闪烁关
}
void LCD1602_init()//LCD1602初始化
{
	LCD1602_writecom(0x38);//显示模式 8位、双行、5*7模式
	LCD1602_writecom(0x0C);//开显示 屏幕开、光标关、闪烁关
	LCD1602_writecom(0x06);//地址自增 光标右移
	LCD1602_writecom(0x01);//清屏幕
//	write_cmd(0x80);//设置数据指针
}

a4. DS1302.h#ifndef _DS1302_H

#define _DS1302_H

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

sbit TSCLK=P3^6;//串行时钟
sbit TIO =P3^4;//数据输入/输出管脚
sbit TCE =P3^5;//复位脚

struct Time{
unsigned int year; //年
unsigned char mon; //月
unsigned char day; //日
unsigned char hour; //时
unsigned char min; //分
unsigned char sec; //秒
unsigned char week; //星期
};

struct alarmtime{
unsigned char mon; //月
unsigned char day; //日
unsigned char hour; //时
unsigned char min; //分
unsigned char week; //星期
unsigned char alarmre:1;//闹钟重复
unsigned char alarmon:1;//闹钟开启
unsigned char music:2;//铃声
};

extern void DS1302_setwp();//打开写保护寄存器

extern void DS1302_clearwp();//关闭写保护寄存器

extern void DS1302_writebyte(unsigned char cmd);//向DS1302写入一个字节

extern unsigned char DS1302_readbyte();//向DS1302读取一个字节

extern void DS1302_writedata(unsigned char cmd,unsigned char DAT);//向DS1302写入数据

extern void DS1302_burstread();//DS1302在突发模式下的读取

extern void DS1302_burstwrite(unsigned char *dat);//DS1302在突发模式下的写入

extern void DS1302_gettime(struct Time *time);//DS1302读取时间

extern void DS1302_settime(struct Time *time);//对DS1302设置当前时间

extern void DS1302_init();//初始化DS1302中的寄存器

#endif


b4. DS1302.c

#include<DS1302.h>

void DS1302_setwp()//打开写保护寄存器
{
	 DS1302_writedata(0x8e,0x80);//WP在写保护寄存器的第七位=1时写保护
	 TCE=0;
	 TSCLK=0;
}
void DS1302_clearwp()//关闭写保护寄存器
{
	 DS1302_writedata(0x8e,0);//0x8e是写保护寄存器的地址
}
void DS1302_writebyte(unsigned char cmd)//向DS1302写入一个字节
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		TSCLK=0;
		if(cmd&0x01)
			TIO=1;
		else
			TIO=0;
		TSCLK=1;
		cmd>>=1;	
	}
}

unsigned char DS1302_readbyte()//向DS1302读取一个字节
{
	unsigned char DAT,i;
	for(i=0;i<8;i++)
	{
		DAT>>=1;
		TSCLK=0;
		if(TIO)
			DAT|=0x80;
		TSCLK=1;	
	}
	return DAT;		
}
void DS1302_writedata(unsigned char cmd,unsigned char DAT)//向DS1302写入数据
{
 		TCE=0;
		TSCLK=0;
		TCE=1;
		DS1302_writebyte(cmd);
		DS1302_writebyte(DAT);
		TCE=0;
}

void DS1302_burstread(unsigned char *dat)//DS1302在突发模式下的读取
{
	 unsigned int i;
	 DS1302_clearwp();//关闭写保护
	 TCE=0;
	 TSCLK=0;
	 TCE=1;
	 DS1302_writebyte(0xbf);//进入时钟突发模式 读最后一个字节为1
	 for(i=0;i<8;i++)//写入8个字节的时钟初始值
	{
		dat[i]=DS1302_readbyte();//在突发模式下可以连续读数据
	}
	DS1302_setwp();//开启写保护
}

void DS1302_burstwrite(unsigned char *dat)//DS1302在突发模式下的写入
{
	 unsigned int i;
	 DS1302_clearwp();//关闭写保护
	 TCE=0;
	 TSCLK=0;
	 TCE=1;
	 DS1302_writebyte(0xbe);//进入时钟突发模式 写最后一个字节为0
	 for(i=0;i<8;i++)//写入8个字节的时钟初始值
	{
		DS1302_writebyte(dat[i]);//在突发模式下可以连续写数据
	}
	DS1302_setwp();//开启写保护
}

void DS1302_gettime(struct Time *time)//DS1302读取时间
{
	unsigned char buf[8];
	DS1302_burstread(buf);//在突发模式下连续读数据
	time->year=buf[6]+0x2000;//BIT6 寄存器6 年,因为DS1302只能是0-99如显示2012年则通过2000这种方法显示年的千位和百位
    time->mon=buf[4];//BIT4 寄存器4
    time->day=buf[3];//BIT3 寄存器3
    time->hour=buf[2];//BIT2 寄存器2
    time->min=buf[1];//BIT1 寄存器1
    time->sec=buf[0];//BIT0 寄存器0
    time->week=buf[5];//BIT5 寄存器5

}
void DS1302_settime(struct Time *time)//对DS1302设置当前时间
{
    unsigned char buf[8];
    buf[7]=0;//寄存器7:最高位一个写保护位,如果这一位是 1,那么是禁止给任何其它寄存器或者那31个字节的RAM写数据的。因此在写数据之前,这一位必须先写成 0。
    buf[6]=time->year;
    buf[5]=time->week;
    buf[4]=time->mon;
    buf[3]=time->day;
    buf[2]=time->hour;
    buf[1]=time->min;
    buf[0]=time->sec;
    DS1302_burstwrite(buf);//在突发模式下可以连续写数据
}
void DS1302_init()//初始化DS1302中的寄存器
{
    struct Time code times={0x18,0x01,0x16,0x14,0x30,0x55,0x03};//一开始初始化的时间 年 月 日 时 分 秒
    DS1302_settime(&times);//设置DS1302为默认的初始时间
}

a5. music.h

#ifndef _music_H__
#define _music_H__

#include<reg52.h>
#include<intrins.h>
 
//C 大调音频定义
#define L1 0xF88C//装进定时器初值里面
#define L2 0xF95B
#define L3 0xFA15
#define L4 0xFA67
#define L5 0xFB04
#define L6 0xFB90
#define L7 0xFC0C
#define M1 0xFC44
#define M2 0xFCAC
#define M3 0xFD09
#define M4 0xFD34
#define M5 0xFD82
#define M6 0xFDC8
#define M7 0xFE06
#define H1 0xFE22
#define H2 0xFE56
#define H3 0xFE85
#define H4 0xFE88
#define H5 0xFEC1
#define H6 0xFEE4
#define H7 0xFF02

sbit beep=P1^5;//蜂鸣器

extern void delay_ms();

extern void playmusic(unsigned char count);//音乐播放函数

#endif

b5. music.c

#include<MUSIC.h>
#include<key.h>
unsigned char i;
unsigned char k,start;
unsigned int code song[3][300]={
//LOSER		
{
H3,4,M5,4,H3,2,H3,2,M5,4,H3,2,H2,2,H3,2,H3,2,H4,2,H3,2,H2,4,H1,4,M3,4,H1,2,H1,2,M3,4,H4,2,H4,2,H3,2,H3,2,H2,4,H1,2,H2,2,H3,4,M5,4,H3,2,H3,2,M5,4,H2,2,H2,2,H3,2,H3,2,H4,2,
H3,2,H2,4,H1,4,H2,4,M7,2,M7,2,H1,4,H4,2,H4,2,H3,2,H2,2,H2,4,H1,2,H2,2,H3,4,M5,4,H3,2,H3,2,M5,4,H3,2,H2,2,H3,2,H3,2,H4,2,H3,2,H2,4,H1,4,M3,4,H1,2,H1,2,M3,4,H4,2,H4,2,H3,2,H3,2,H2,4,H1,2,H2,2,H3,4,M5,4,H3,2,H3,2,M5,4,H2,2,H2,2,H3,2,H3,2,H4,2,
H3,2,H2,4,H1,4,H2,4,M7,2,M7,2,H1,4,H4,2,H4,2,H3,2,H2,2,H2,4,H1,2,H2,2,H1,4,H2,4,H3,4,0xff
},

{
L5,16,M1,8,M3,12,M1,4,M2,8,M1,24,M1,24,L5,16,M1,8,
M3,12,M1,4,M3,8,M2,24,M2,24,L6,16,M2,8,
M4,12,M3,4,M4,8,M2,24,M2,24,M5,16,M2,8,L7,12,L5,4,M2,8,
M1,24,M1,24,M2,16,M2,8,M2,16,M1,8,
M2,16,M3,8,M4,24,M2,16,M2,8,M2,8,M1,8,M2,8,
M3,24,M3,24,M2,16,M2,8,M2,16,M1,8,
M2,16,M3,8,M4,24,L7,16,L5,8,M4,12,M3,4,M2,8,
M1,24,M1,24,0xff
},

{
 M7,8,M6,8,M6,6,M6,12,M1,8,M6,8,M7,12,M6,4,M6,4,M6,4,M6,8,M5,4,M5,5,M5,5,M5,4,M6,8,M7,8,M6,8,M6,6,M6,12,M1,8,M6,8,M7,12,M6,4,M6,4,M6,4,M7,8,M6,8,M6,6,M6,12,M1,8,M6,8,M7,12,M6,4,M6,4,M6,4,
 M7,8,M6,8,M6,6,M6,12,M1,8,M6,8,M7,12,M6,4,M6,4,M6,4,M6,8,M5,4,M5,5,M5,5,M5,4,M6,8,M7,8,M6,8,M6,6,M6,12,M1,8,M6,8,M7,12,M6,4,M6,4,M6,4,M7,8,M6,8,M6,6,M6,12,M1,8,M6,8,M7,12,M6,4,M6,4,M6,4,0xff 
}
	
};

void delay_ms()//节拍控制+按键退出
{
	unsigned int i=300;
	while(i--)
	{
	 key_scan();//更新按键状态
	 key_driver();//检测按键状态
	}
}

void playmusic(unsigned char count)//count是曲目编号
{
	unsigned char j,playcount=0;
	TR0=0;
	beep=0;
	k=count;
	TR0=1;
	while(start&&playcount!=1)
	 {
		 while(song[k][i]!=0xff&&start)	//遍历整首歌
		 {
				TH0=song[k][i]/256;
				TL0=song[k][i]%256;
				for(j=0;j<song[k][i+1];j++)	//节拍延时
				{
					delay_ms();//控制节拍
				}
				i+=2;	
		 }
		playcount++;
		i=0;   //播放完一首要清0
	}			
	playcount=0;
	beep=0;
	start=1;
	TR0=0;	 
}


a6. DS18B20.h

#ifndef _DS18B20_H__
#define _DS18B20_H__

#include<reg52.h>

sbit DQ=P3^7;//单线运用的数据输入/输出引脚

extern void Delay_ms(unsigned int y);

extern unsigned char DS18B20init();//DS18B20初始化函数

extern void DS18B20writebyte(unsigned char dat);//DS18B20写字节函数

extern unsigned char DS18B20readbyte();//DS18B20读字节函数

extern void DS18B20changetemp();//让18B20开始转换温度函数

extern int DS18B20readtemp();//读取温度函数 

#endif

b6. DS18B20.h

#include<DS18B20.H>

//在单总线上面要精确的延时时间,误差很大单总线通信会失败

void Delay_ms(unsigned int y)//参数改变延时时间
{
  unsigned int x;
  for(;y>0;y--)
  {
    for(x=110;x>0;x--);//1ms的延时
  }
}

//DS18B20测温的话首先要为DS18B20初始化
unsigned char DS18B20init()//DS18B20初始化函数
{
  unsigned char i=0;
  DQ=0;//将总线延时480到960微秒
  i = 70;	
  while(i--);//延时642us
  DQ=1;//然后拉高总线,如果DS18B20初始化成功会将在15us~60us产生一个由DS18B20所返回的低电平“0”,表面DS18B20存在
  i=0;
  while(DQ)//判断总线电平,低电平表明DS18B20存在退出循环
  {
	Delay_ms(1);//延时1ms
	i++;
	if(i>5)//等待5ms的超时判断
	 {
		return 0;//初始化失败
	 }
  }
  return 1;//返回1的话表示DS18B20存在初始化成功
}

//对DS18B20进行写字节或读字节

void DS18B20writebyte(unsigned char dat)//DS18B20写字节函数 按地位到高位的顺序发送数据(一次只发送一位) 
{
	unsigned int i,j;
	for(i=0;i<8;i++)//一个字节有8位数据
	{
		DQ=0;//将总线拉低低电平
		j++;
		DQ=dat&0x01;//写入一个数据,从最低位开始 最低位是1还是0
		j=6;//延时十几微妙 
		while(j--);//延时68us,延时时间最少60us
		DQ=1;//拉高总线,至少1us给总线恢复时间才能接着写入第二个数值
		dat>>=1;//每次只发送一位所以要进行移位 右移
	}
}

unsigned char DS18B20readbyte()//DS18B20读字节函数
{
	unsigned char byte,bi;//bi用来保存每一位的数据,byte用来返回出去
	unsigned int i,j;	
	for(i=0;i<8;i++)//循环8次 一次读一位
	{
		DQ=0;//将总线拉低
		j++;//延时大于1us		 
		DQ=1;//总线拉高
		j++;
		j++;//延时6us等待数据稳定
		bi=DQ;//读取数据得到状态位,先从最低位开始读取
	    byte=(byte>>1)|(bi<<7);//将byte右移一位(循环7次),然后获取与上右移7位后的bi,注意移动之后移掉那位补0。						  
		j=4;
		while(j--);//读取完之后等待48us再接着读取下一个数
	}//重复步骤直到读完一个字节				
	return byte;
}

void DS18B20changetemp()//让18b20开始转换温度函数
{
	DS18B20init();//先让DS18B20初始化
	Delay_ms(1);//延时1ms等待传感器稳定
	DS18B20writebyte(0xcc);//跳过ROM操作命令,功能是忽略64位ROM地址,直接向DS18B20发温度变换命令,适用于单机工作(一个温度传感器进行检测)		 
	DS18B20writebyte(0x44);//温度转换命令,功能是启动DS18B20进行温度转换,默认使用12位进行转换,12位转换时最长为750ms(9位为93.75ms),结果存入内部9字节RAM中
	//Delay_ms(100);//等待转换成功,而如果你是一直刷着的话,就不用这个延时了 
}

int DS18B20readtemp()//读取温度函数
{
	int temp=0;
	unsigned char tmh,tml;//温度的低字节和高字节数据
	EA=0;
	DS18B20changetemp();//先写入转换命令
    DS18B20init();
	Delay_ms(1);
	DS18B20writebyte(0xcc);//跳过ROM操作命令
	DS18B20writebyte(0xbe);//发送读取温度命令,功能是读取内部RAM中9字节的内容
	tml=DS18B20readbyte();//读取温度值共16位,先读低字节
	tmh=DS18B20readbyte();//再读高字节
	temp=tmh;
	temp<<=8;
	temp|=tml;
	EA=1;
	return temp;
}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值