单片机电子钟程序完美版(带闹钟温度功能)

发布者:SereneNature7最新更新时间:2015-01-15 来源: 51hei关键字:单片机  电子钟  闹钟  温度功能 手机看文章 扫描二维码
随时随地手机看文章

本电子钟已经全部测试OK,带闹钟功能,年月日时分秒星期温度,四个按键可设置闹钟调节时间,温度可以显示正125度到负的55度之间,时间走时的话,我测试了一个月,误差不到1分钟。本人已经录制成视频,视频里面有详细的介绍,感兴趣的可以看看 。视频及多图还有源代码的地址: http://www.51hei.com/bbs/dpj-26057-1.html

程序:

#include 
#include 
#define uchar unsigned char
#define uint unsigned int
sbit rs=P1^0;//寄存器选择
sbit rw=P1^1;//读写信号线
sbit lcden=P1^2;//led使能端

sbit scl=P1^3;//时钟线
sbit rst=P1^5;//复位线
sbit io=P1^4;//数据口

sbit key_set_time=P3^4;//设置时间键
sbit key_add=P3^5;//加键
sbit key_minus=P3^6;//减键
sbit key_set_alarm=P3^7;//设置闹钟键
sbit bee=P1^6;//蜂鸣器接口
sbit dq=P1^7;//ds18b20测温

uchar getTimebuf[7];//存放时间数据
uchar time[]={"  :  :  "};//时间格式字符串
uchar date[]={"20  -  -  "};//日期格式字符串
uchar weeklist[]={"SunMonTueWedThuFriSat"};//星期字符列表
uchar week[]={"   "};//星期格式字符串

int count;//设定秒分时日月星期年的时候count的值分别为1235647
int alarm;//是否进入闹钟设置界面 123分别代表开关 分 小时的设置
int isOpen;//闹钟是否开启  默认不开启
int fen,shi;//闹钟的分钟小时
int isRing;//闹钟是否在响

uchar isInit_1302;//是否初始化时钟完毕

int num;
int temperature;//温度
int temp_flag;//温度正负标志

void delay(uint x){
	int y;
	while(x--){
		for(y=100;y>0;y--);
	}
}
void write_1602com(uchar com){
	//1602写指令
	rs=0;
	lcden=0;
	P2=com;
	delay(5);
	lcden=1;
	delay(5);
	lcden=0;
}
void write_1602data(uchar dat){
	//1602写数据
	rs=1;
	lcden=0;
	P2=dat;
	delay(5);
	lcden=1;
	delay(5);
	lcden=0;
}
void init_1602(){
	//初始化1602液晶
	rw=0;
	lcden=0;
	write_1602com(0x38);//设置显示模式
	write_1602com(0x0c);//显示开关及光标是否显示和闪动
	write_1602com(0x06);//光标移动方向
	write_1602com(0x01);//清屏
}
void write_ds1302_byte(uchar temp){
	//ds1302写一个字节数据
	uchar i;
	for(i=0;i<8;i++){
		io=temp&0x01;//将数据放到IO口上
		scl=0;//scl为低时准备数据
		scl=1;//上升沿写入
		temp>>=1;
	}
}
void write_ds1302(uchar add,uchar dat){
	//向地址add写入数据dat
	rst=0;
	scl=0;
	rst=1;
	write_ds1302_byte(add);
	write_ds1302_byte(dat);
	scl=1;
	rst=0;
}
uchar read_ds1302(uchar add){
	//ds1302读数据
	uchar i,dat;
	rst=0;
	scl=0;
	rst=1;
	write_ds1302_byte(add);//首先写入要读的数据处的地址
	for(i=0;i<8;i++){
		if(io==1){
			dat|=0x80;
		}
		scl=1;
		scl=0;//下降沿读取数据
		dat>>=1;
	}
	scl=1;
	rst=0;
	return dat;
}
void read_time(uchar curr_time[]){
	  uchar i;
	  uchar ucAddr = 0x81;
	  for (i=0;i<7;i++){
		curr_time[i] = read_ds1302(ucAddr);//格式为: 秒 分 时 日 月 星期 年 
		ucAddr += 2;
	  }
}[page]
void set_time(uchar *pSecDa){
	//设定时间
	uchar i;
	uchar ucAddr = 0x80;
	write_ds1302(0x8e,0x00);	
	for(i =7;i>0;i--){ 
		write_ds1302(ucAddr,*pSecDa); //秒 分 时 日 月 星期 年
		pSecDa++;
		ucAddr+=2;
	}
	write_ds1302(0x8e,0x80);
}
void init_ds1302(){
	//ds1302初始化
	isInit_1302=read_ds1302(0x81);//读出时钟状态
	if(isInit_1302&0x80){//说明没有初始化
		write_ds1302(0x8e,0x00);//关闭写保护  以后一直开着
		write_ds1302(0x90,0xa5); //辅助电源充电命令 一个二极管  一个2K电阻
		write_ds1302(0x80,0x00);//秒 CH置0 开启时钟
		write_ds1302(0x82,0x59);//分
		write_ds1302(0x84,0x10);//时
		write_ds1302(0x86,0x07);//日
		write_ds1302(0x88,0x05);//月
		write_ds1302(0x8a,0x04);//星期
		write_ds1302(0x8c,0x14);//年
		write_ds1302(0x8e,0x80);
	}
}
char int_to_char(int temp){
	//把0到9对应的数字转为字符
	char x='0';
	switch(temp){
		case 0:x='0';break;
		case 1:x='1';break;
		case 2:x='2';break;
		case 3:x='3';break;
		case 4:x='4';break;
		case 5:x='5';break;
		case 6:x='6';break;
		case 7:x='7';break;
		case 8:x='8';break;
		case 9:x='9';break;
	}
	return x;
}
int ds18b20_read_temp();
void display(){
	uchar bai,shi,ge,point,fuhao;
	read_time(getTimebuf);//时时读取时间
    time[6]=(getTimebuf[0])/16+48;//格式化时间秒
    time[7]=(getTimebuf[0])%16+48;

    time[3]=(getTimebuf[1])/16+48;//格式化时间分
    time[4]=(getTimebuf[1])%16+48;

    time[0]=(getTimebuf[2])/16+48;//格式化时间小时
    time[1]=(getTimebuf[2])%16+48;

    date[8]=getTimebuf[3]/16+48;//格式化日期日
    date[9]=getTimebuf[3]%16+48;

    date[5]=getTimebuf[4]/16+48;//格式化日期月
    date[6]=getTimebuf[4]%16+48;

    date[2]=getTimebuf[6]/16+48;//格式化日期年
    date[3]=getTimebuf[6]%16+48;

    week[0]=weeklist[(getTimebuf[5]%10)*3];//格式化星期
    week[1]=weeklist[(getTimebuf[5]%10)*3+1];
    week[2]=weeklist[(getTimebuf[5]%10)*3+2];
	
	write_1602com(0x80+1);
	for(num=0;num<10;num++){
		write_1602data(date[num]);
	}

	write_1602data(' ');
	for(num=0;num<3;num++){
		write_1602data(week[num]);
	}

	write_1602com(0x80+0x40);
	for(num=0;num<8;num++){
		write_1602data(time[num]);
	}
	
	//显示温度值
	write_1602com(0x80+0x40+8);//设置数据指针
	temperature=ds18b20_read_temp();
	bai=temperature/1000+0x30;
	shi=temperature%1000/100+0x30;
	ge=temperature%100/10+0x30;
	point=temperature%100%10+0x30;
	if(temp_flag==1){//说明为正数  不显示符号位 125.6 25.7两种
		fuhao=0x20;//显示空白
		if(bai==0x30){
			bai=0x20;//如果百位为0  不显示
			if(shi==0x30){
				shi=0x20;//如果百位为0  十位也为0  都不显示
			}
		}
		write_1602data(fuhao);
		write_1602data(bai);
		write_1602data(shi);
	}else{
		fuhao=0x2d;//显示负号  -2.5  -25.8两种
		write_1602data(0x20);//因为负数最低到55,所以不显示百位
		if(shi==0x30){	
			write_1602data(0x20);
			write_1602data(fuhao);
		}else{
			write_1602data(fuhao);
			write_1602data(shi);
		}
	}
	write_1602data(ge);
	write_1602data('.');
	write_1602data(point);
	write_1602data(0xdf);
	write_1602data('C');
}
void display_alarm(uchar add,int dat){
	//把设定的时分显示出来
	int x,y;
	x=dat/10;
	y=dat%10;
	write_1602com(add);
	write_1602data(int_to_char(x));
	write_1602com(add+1);//防止写后地址自动向后加一  光标闪烁看不到
	write_1602data(int_to_char(y));
	write_1602com(add+1);
}
void init_alarm(){
	//闹钟设置界面  只有首次进入才执行
	uchar code x[]="SET ALARM";
	uchar i;
	if(alarm==0){
		write_1602com(0x01);//清屏
		write_1602com(0x80+3);//设置数据指针
		for(i=0;i<9;i++){
			write_1602data(x[i]);
		}
		display_alarm(0x80+0x40+5,shi);//载入闹钟的时分
		write_1602com(0x80+0x40+7);
		write_1602data(':');
		display_alarm(0x80+0x40+8,fen);
		if(isOpen){//初始化的时候如果已经设定闹钟则显示ON
			write_1602com(0x80+0x40+13);
			write_1602data(' ');
			write_1602data('O');
			write_1602data('N');
		}else{
			write_1602com(0x80+0x40+13);
			write_1602data('O');
			write_1602data('F');
			write_1602data('F');
		}
	}
}
void key_scan(){
	int i;
	uchar code tips1[]="SET SUCCESS";//闹钟设置成功的提示
	uchar code tips2[]="CANCEL SUCCESS";//取消闹钟的提示
	if(key_set_time==0){//检测是否按下
		delay(10);//消抖
		if(key_set_time==0){//再次检测是否按下
			while(!key_set_time);//检测是否松开
			delay(10);//延时消抖
			while(!key_set_time);//再次检测是否松开
			if(alarm==0){//当没有显示闹钟界面时才显示时间设定
				count++;
				write_ds1302(0x80,0x80);//让时钟停止
				if(count==8){
					//继续走时,说明时间已经设定好了
					write_1602com(0x0c);//让光标消失
					write_ds1302(0x80,0);//让时钟继续
					set_time(getTimebuf);//写入新的时间
					count=0;
					return;
				}
				switch(count){
					case 1:
						write_1602com(0x80+0x40+7);//在秒的位置
						break;
					case 2:
						write_1602com(0x80+0x40+4);//在分的位置
						break;
					case 3:
						write_1602com(0x80+0x40+1);//在时的位置
						break;
					case 4:
						write_1602com(0x80+14);//在星期的位置
						break;
					case 5:
						write_1602com(0x80+10);//在日的位置
						break;
					case 6:
						write_1602com(0x80+7);//在月的位置
						break;
					case 7:
						write_1602com(0x80+4);//在年的位置
						break;
				}
				write_1602com(0x0f);//让光标闪烁
			}
		}
	}
	if(key_add==0){//检测是否按下
		delay(10);//消抖
		if(key_add==0){//再次检测是否按下
			while(!key_add);//检测是否松开
			delay(10);//延时消抖
			while(!key_add);//再次检测是否松开
			if(count!=0){
				switch(count){
				case 1:
					//在秒的位置
					getTimebuf[0]++;
					if(getTimebuf[0]==0x5a){
						getTimebuf[0]=0;
					}
					if(getTimebuf[0]==0x4a){
						getTimebuf[0]=0x50;
					}
					if(getTimebuf[0]==0x3a){
						getTimebuf[0]=0x40;
					}
					if(getTimebuf[0]==0x2a){
						getTimebuf[0]=0x30;
					}
					if(getTimebuf[0]==0x1a){
						getTimebuf[0]=0x20;
					}
					if(getTimebuf[0]==0x0a){
						getTimebuf[0]=0x10;
					}
					time[6]=(getTimebuf[0])/16+48;//格式化时间秒
					time[7]=(getTimebuf[0])%16+48;
					write_1602com(0x80+0x40+6);//在秒的位置
					write_1602data(time[6]);
					write_1602com(0x80+0x40+7);//在秒的位置
					write_1602data(time[7]);
					write_1602com(0x80+0x40+7);//让光标在秒的位置闪烁
					break;
				case 2:
					//在分的位置
					getTimebuf[1]++;
					if(getTimebuf[1]==0x5a){
						getTimebuf[1]=0;
					}
					if(getTimebuf[1]==0x4a){
						getTimebuf[1]=0x50;
					}
					if(getTimebuf[1]==0x3a){
						getTimebuf[1]=0x40;
					}
					if(getTimebuf[1]==0x2a){
						getTimebuf[1]=0x30;
					}
					if(getTimebuf[1]==0x1a){
						getTimebuf[1]=0x20;
					}
					if(getTimebuf[1]==0x0a){
						getTimebuf[1]=0x10;
					}
					time[3]=(getTimebuf[1])/16+48;//格式化时间分
					time[4]=(getTimebuf[1])%16+48;
					write_1602com(0x80+0x40+3);//在分的位置
					write_1602data(time[3]);
					write_1602com(0x80+0x40+4);//在分的位置
					write_1602data(time[4]);
					write_1602com(0x80+0x40+4);//让光标在分的位置闪烁
					break;
				case 3:
					//在时的位置
					getTimebuf[2]++;
					if(getTimebuf[2]==0x24){
						getTimebuf[2]=0;
					}
					if(getTimebuf[2]==0x1a){
						getTimebuf[2]=0x20;
					}
					if(getTimebuf[2]==0x0a){
						getTimebuf[2]=0x10;
					}
					time[0]=(getTimebuf[2])/16+48;//格式化时间小时
					time[1]=(getTimebuf[2])%16+48;
					write_1602com(0x80+0x40+0);//在小时的位置
					write_1602data(time[0]);
					write_1602com(0x80+0x40+1);
					write_1602data(time[1]);
					write_1602com(0x80+0x40+1);
					break;
				case 4:
					//在星期的位置
					getTimebuf[5]++;
					if(getTimebuf[5]==0x08){
						getTimebuf[5]=0x01;
					}
					if((getTimebuf[5]%10)*3==21){//轮完了  重新开始
						week[0]=weeklist[0];
						week[1]=weeklist[1];
						week[2]=weeklist[2];
					}else{
						week[0]=weeklist[(getTimebuf[5]%10)*3];//格式化星期
						week[1]=weeklist[(getTimebuf[5]%10)*3+1];
						week[2]=weeklist[(getTimebuf[5]%10)*3+2];
					}
					write_1602com(0x80+12);
					write_1602data(week[0]);
					write_1602com(0x80+13);
					write_1602data(week[1]);
					write_1602com(0x80+14);
					write_1602data(week[2]);
					write_1602com(0x80+14);
					break;
				case 5:
					//在日的位置
					getTimebuf[3]++;
					if(getTimebuf[3]==0x32){
						getTimebuf[3]=0x01;
					}
					if(getTimebuf[3]==0x2a){
						getTimebuf[3]=0x30;
					}
					if(getTimebuf[3]==0x1a){
						getTimebuf[3]=0x20;
					}
					if(getTimebuf[3]==0x0a){
						getTimebuf[3]=0x10;
					}
					date[8]=(getTimebuf[3])/16+48;
					date[9]=(getTimebuf[3])%16+48;
					write_1602com(0x80+9);
					write_1602data(date[8]);
					write_1602com(0x80+10);
					write_1602data(date[9]);
					write_1602com(0x80+10);
					break;
				case 6:
					//在月的位置
					getTimebuf[4]++;
					if(getTimebuf[4]==0x13){
						getTimebuf[4]=0x01;
					}
					if(getTimebuf[4]==0x0a){
						getTimebuf[4]=0x10;
					}
					date[5]=(getTimebuf[4])/16+48;
					date[6]=(getTimebuf[4])%16+48;
					write_1602com(0x80+6);
					write_1602data(date[5]);
					write_1602com(0x80+7);
					write_1602data(date[6]);
					write_1602com(0x80+7);
					break;
				case 7:
					//在年的位置
					getTimebuf[6]++;
					if(getTimebuf[6]==0x9a){
						getTimebuf[6]=0x00;
					}
					if(getTimebuf[6]==0x8a){
						getTimebuf[6]=0x90;
					}
					if(getTimebuf[6]==0x7a){
						getTimebuf[6]=0x80;
					}
					if(getTimebuf[6]==0x6a){
						getTimebuf[6]=0x70;
					}
					if(getTimebuf[6]==0x5a){
						getTimebuf[6]=0x60;
					}
					if(getTimebuf[6]==0x4a){
						getTimebuf[6]=0x50;
					}
					if(getTimebuf[6]==0x3a){
						getTimebuf[6]=0x40;
					}
					if(getTimebuf[6]==0x2a){
						getTimebuf[6]=0x30;
					}
					if(getTimebuf[6]==0x1a){
						getTimebuf[6]=0x20;
					}
					if(getTimebuf[6]==0x0a){
						getTimebuf[6]=0x10;
					}
					date[2]=(getTimebuf[6])/16+48;
					date[3]=(getTimebuf[6])%16+48;
					write_1602com(0x80+3);
					write_1602data(date[2]);
					write_1602com(0x80+4);
					write_1602data(date[3]);
					write_1602com(0x80+4);
					break;
				}
			}
			if(alarm!=0){
				switch(alarm){
					case 1:
						//调节闹钟的开与关
						if(isOpen==0){
							isOpen=1;
							write_1602com(0x80+0x40+13);
							write_1602data(' ');
							write_1602data('O');
							write_1602data('N');
						}else{
							isOpen=0;
							write_1602com(0x80+0x40+13);
							write_1602data('O');
							write_1602data('F');
							write_1602data('F');
						}
						//防止写后地址自动向后加一  光标闪烁看不到
						write_1602com(0x80+0x40+15);
						break;
					case 2:
						//调节闹钟的分
						fen++;
						if(fen==60){
							fen=0;
						}
						display_alarm(0x80+0x40+8,fen);
						break;
					case 3:
						//调节闹钟的小时
						shi++;
						if(shi==24){
							shi=0;
						}
						display_alarm(0x80+0x40+5,shi);
						break;
				}
			}
		}
	}
	if(key_minus==0){//检测是否按下
		delay(10);//消抖
		if(key_minus==0){//再次检测是否按下
			while(!key_minus);//检测是否松开
			delay(10);//延时消抖
			while(!key_minus);//再次检测是否松开
			if(count!=0){
				switch(count){
				case 1:
					//在秒的位置
					getTimebuf[0]--;
					if(getTimebuf[0]==0xff){
						getTimebuf[0]=0x59;
					}
					if(getTimebuf[0]==0x4f){
						getTimebuf[0]=0x49;
					}
					if(getTimebuf[0]==0x3f){
						getTimebuf[0]=0x39;
					}
					if(getTimebuf[0]==0x2f){
						getTimebuf[0]=0x29;
					}
					if(getTimebuf[0]==0x1f){
						getTimebuf[0]=0x19;
					}
					if(getTimebuf[0]==0x0f){
						getTimebuf[0]=0x09;
					}
					time[6]=(getTimebuf[0])/16+48;//格式化时间秒
					time[7]=(getTimebuf[0])%16+48;
					write_1602com(0x80+0x40+6);//在秒的位置
					write_1602data(time[6]);
					write_1602com(0x80+0x40+7);//在秒的位置
					write_1602data(time[7]);
					write_1602com(0x80+0x40+7);//让光标在秒的位置闪烁
					break;
				case 2:
					//在分的位置
					getTimebuf[1]--;
					if(getTimebuf[1]==0xff){
						getTimebuf[1]=0x59;
					}
					if(getTimebuf[1]==0x4f){
						getTimebuf[1]=0x49;
					}
					if(getTimebuf[1]==0x3f){
						getTimebuf[1]=0x39;
					}
					if(getTimebuf[1]==0x2f){
						getTimebuf[1]=0x29;
					}
					if(getTimebuf[1]==0x1f){
						getTimebuf[1]=0x19;
					}
					if(getTimebuf[1]==0x0f){
						getTimebuf[1]=0x09;
					}
					time[3]=(getTimebuf[1])/16+48;//格式化时间分
					time[4]=(getTimebuf[1])%16+48;
					write_1602com(0x80+0x40+3);//在分的位置
					write_1602data(time[3]);
					write_1602com(0x80+0x40+4);//在分的位置
					write_1602data(time[4]);
					write_1602com(0x80+0x40+4);//让光标在分的位置闪烁
					break;
				case 3:
					//在时的位置
					getTimebuf[2]--;
					if(getTimebuf[2]==0xff){
						getTimebuf[2]=0x23;
					}
					if(getTimebuf[2]==0x1f){
						getTimebuf[2]=0x19;
					}
					if(getTimebuf[2]==0x0f){
						getTimebuf[2]=0x09;
					}
					time[0]=(getTimebuf[2])/16+48;//格式化时间小时
					time[1]=(getTimebuf[2])%16+48;
					write_1602com(0x80+0x40+0);//在小时的位置
					write_1602data(time[0]);
					write_1602com(0x80+0x40+1);
					write_1602data(time[1]);
					write_1602com(0x80+0x40+1);
					break;
				case 4:
					//在星期的位置
					getTimebuf[5]--;
					if(getTimebuf[5]==0){
						getTimebuf[5]=0x07;
					}
					if((getTimebuf[5]%10)*3==21){//轮完了  重新开始
						week[0]=weeklist[0];
						week[1]=weeklist[1];
						week[2]=weeklist[2];
					}else{
						week[0]=weeklist[(getTimebuf[5]%10)*3];//格式化星期
						week[1]=weeklist[(getTimebuf[5]%10)*3+1];
						week[2]=weeklist[(getTimebuf[5]%10)*3+2];
					}
					write_1602com(0x80+12);
					write_1602data(week[0]);
					write_1602com(0x80+13);
					write_1602data(week[1]);
					write_1602com(0x80+14);
					write_1602data(week[2]);
					write_1602com(0x80+14);
					break;
				case 5:
					//在日的位置
					getTimebuf[3]--;
					if(getTimebuf[3]==0){
						getTimebuf[3]=0x31;
					}
					if(getTimebuf[3]==0x2f){
						getTimebuf[3]=0x29;
					}
					if(getTimebuf[3]==0x1f){
						getTimebuf[3]=0x19;
					}
					if(getTimebuf[3]==0x0f){
						getTimebuf[3]=0x09;
					}
					date[8]=(getTimebuf[3])/16+48;
					date[9]=(getTimebuf[3])%16+48;
					write_1602com(0x80+9);
					write_1602data(date[8]);
					write_1602com(0x80+10);
					write_1602data(date[9]);
					write_1602com(0x80+10);
					break;
				case 6:
					//在月的位置
					getTimebuf[4]--;
					if(getTimebuf[4]==0){
						getTimebuf[4]=0x12;
					}
					if(getTimebuf[4]==0x0f){
						getTimebuf[4]=0x09;
					}
					date[5]=(getTimebuf[4])/16+48;
					date[6]=(getTimebuf[4])%16+48;
					write_1602com(0x80+6);
					write_1602data(date[5]);
					write_1602com(0x80+7);
					write_1602data(date[6]);
					write_1602com(0x80+7);
					break;
				case 7:
					//在年的位置
					getTimebuf[6]--;
					if(getTimebuf[6]==0xff){
						getTimebuf[6]=0x99;
					}
					if(getTimebuf[6]==0x8f){
						getTimebuf[6]=0x89;
					}
					if(getTimebuf[6]==0x7f){
						getTimebuf[6]=0x79;
					}
					if(getTimebuf[6]==0x6f){
						getTimebuf[6]=0x69;
					}
					if(getTimebuf[6]==0x5f){
						getTimebuf[6]=0x59;
					}
					if(getTimebuf[6]==0x4f){
						getTimebuf[6]=0x49;
					}
					if(getTimebuf[6]==0x3f){
						getTimebuf[6]=0x39;
					}
					if(getTimebuf[6]==0x2f){
						getTimebuf[6]=0x29;
					}
					if(getTimebuf[6]==0x1f){
						getTimebuf[6]=0x19;
					}
					if(getTimebuf[6]==0x0f){
						getTimebuf[6]=0x09;
					}
					date[2]=(getTimebuf[6])/16+48;
					date[3]=(getTimebuf[6])%16+48;
					write_1602com(0x80+3);
					write_1602data(date[2]);
					write_1602com(0x80+4);
					write_1602data(date[3]);
					write_1602com(0x80+4);
					break;
				}
			}
			if(alarm!=0){
				switch(alarm){
					case 1:
						//调节闹钟的开与关
						if(isOpen==0){
							isOpen=1;
							write_1602com(0x80+0x40+13);
							write_1602data(' ');
							write_1602data('O');
							write_1602data('N');
						}else{
							isOpen=0;
							write_1602com(0x80+0x40+13);
							write_1602data('O');
							write_1602data('F');
							write_1602data('F');
						}
						//防止写后地址自动向后加一  光标闪烁看不到
						write_1602com(0x80+0x40+15);
						break;
					case 2:
						//调节闹钟的分
						fen--;
						if(fen<0){
							fen=59;
						}
						display_alarm(0x80+0x40+8,fen);
						break;
					case 3:
						//调节闹钟的小时
						shi--;
						if(shi<0){
							shi=23;
						}
						display_alarm(0x80+0x40+5,shi);
						break;
				}
			}
		}
	}
	if(key_set_alarm==0){//检测是否按下
		delay(10);//消抖
		if(key_set_alarm==0){//再次检测是否按下
			while(!key_set_alarm);//检测是否松开
			delay(10);//延时消抖
			while(!key_set_alarm);//再次检测是否松开
			if(count==0){//时间在正常走动的时候才能设置闹钟
				init_alarm();
				alarm++;//说明进入闹钟设置界面
				if(alarm==4){
					alarm=0;//说明闹钟设置完毕
					write_1602com(0x01);//清屏以便显示时间
					write_1602com(0x0c);//关闭光标
					//显示设置成功或取消的提示
					if(isOpen){
						write_1602com(0x80+2);
						for(i=0;i<11;i++){
							write_1602data(tips1[i]);
						}
					}else{
						write_1602com(0x80+1);
						for(i=0;i<14;i++){
							write_1602data(tips2[i]);
						}
					}
					//延时2ms后清屏显示时间
					delay(2000);
					write_1602com(0x01);
				}else{
					switch(alarm){
						case 1:
							write_1602com(0x80+0x40+15);
							break;
						case 2:
							write_1602com(0x80+0x40+9);
							break;
						case 3:
							write_1602com(0x80+0x40+6);
							break;
					}
					write_1602com(0x0f);
				}
			}
		}
	}
}[page]
void beep(){
	//检测闹钟  并且报警
	if(time[0]==int_to_char(shi/10)&&time[1]==int_to_char(shi%10)&&time[3]==int_to_char(fen/10)&&time[4]==int_to_char(fen%10)){
		isRing=1;//闹钟响起,此时如果进入闹钟设置界面 改变时分,闹钟就关闭了
		bee=0;
		delay(250);
		bee=1;
		delay(250);
	}else{
		isRing=0;//关闭闹钟或者一分钟后闹钟自动关闭
		bee=1;
	}
}
void delay1(int i){
	while(i--);
}
void ds18b20_init(){
	uchar x=0;
	dq = 1;    //DQ复位
	delay1(8);  //稍做延时
	dq = 0;    //单片机将DQ拉低
	delay1(80); //精确延时 大于 480us
	dq = 1;    //拉高总线
	delay1(14);
	x=dq;      //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
	delay1(20);
}
uchar ds18b20_read(){
	//读一个字节
	uchar i=0;
	uchar dat = 0;
	for (i=8;i>0;i--)
	{
		dq = 0; // 给脉冲信号
		dat>>=1;
		dq = 1; // 给脉冲信号
		if(dq)
			dat|=0x80;
		delay1(4);
	}
	return(dat);
}
void ds18b20_write(char dat){
	//写一个字节
	uchar i=0;
	for (i=8; i>0; i--)
	{
		dq = 0;
		dq = dat&0x01;
		delay1(5);
		dq = 1;
		dat>>=1;
	}
}
int ds18b20_read_temp(){
	//读取温度
	uchar low;
	uchar high;
	unsigned long tmp;
	float value;
	int t;//温度
	ds18b20_init();
	ds18b20_write(0xCC); //跳过读序列号的操作
	ds18b20_write(0x44); //启动温度转换
	ds18b20_init();
	ds18b20_write(0xCC); //跳过读序列号的操作
	ds18b20_write(0xBE); //读取温度寄存器  共九个  前两个代表温度
	low=ds18b20_read();//低八位数据
	high=ds18b20_read();//高八位数据

	tmp=high;
	tmp<<=8;
	tmp=tmp|low;
	//此处有正负之分
	if(tmp>=63488){//ffff f000 0000 0000-->(f800)
		temp_flag=0;
		//8位全为1时,加1才进位
		if((~low)==0xff){//判断low取反加1之后是否进位
			high=(~high)+1;
			low=0;
		}else{
			high=~high;
			low=(~low)+1;
		}
		tmp=high*256+low;
	}else{
		temp_flag=1;
	}
	value=tmp*0.0625;
	t=value*10+((temp_flag==1)?+0.5:-0.5);//放大十倍输出并四舍五入
	return t;
}
void main(){
	init_1602();
	init_ds1302();
	while(1){
		if(isOpen){//只有开启闹钟的时候才检测
			beep();//不断检测闹钟
		}
		key_scan();
		if(count==0&&alarm==0){//没有设定时间  也没有在闹钟界面的时候时间才显示
			display();
		}
	}
}
关键字:单片机  电子钟  闹钟  温度功能 引用地址:单片机电子钟程序完美版(带闹钟温度功能)

上一篇:搞定Keil的cant execute C:\Keil\C51\BIN\A51.EXE
下一篇:Verilog乘法运算结果为0问题的解决

推荐阅读最新更新时间:2024-03-16 13:51

单片机应用系统的可靠性分析
随着单片机在国防、金融、工业控制等重要领域应用越来越广泛,单片机应用系统的可靠性越来越成为人们关注的一个重要课题。单片机应用系统的可靠性是由多种因素决定的,大体分为硬件系统可靠性设计和软件系统可靠性设计。 一、硬件系统可靠性设计 (1)选优设计 在系统硬件设计和加工时,应该选用质量好的接插件,设计好工艺结构;选用合格的元器件,进行严格的测试、筛选和老化;设计时技术参数(如负载)要留有一定的余量或降额使用元器件;提高印制板和组装的质量。 (2)冗余与容错设计 保证单片机应用系统100%无故障是不可能的。容错是指当系统的某个部件发生故障时,系统仍能完全正常地工作,即给系统增加容忍故障的能力。为使系统具有容错
[单片机]
<font color='red'>单片机</font>应用系统的可靠性分析
将程序下载到单片机
首先,我们要把硬件连接好,把板子插到我们的电脑上,打开设备管理器查看所使用的是哪个 COM 口,如图 2-21 所示,找到“USB-SERIAL CH340(COM5)”这一项,这里最后的数字就是开发板目前所使用的 COM 端口号。 图 2-21 查看COM口 然后 STC 系列单片的下载软件——STC-ISP,如图 2-22 所示。 图2-22 程序下载设置 下载软件列出了 5 个步骤:第一步,选择单片机型号,我们现在用的单片机型号是STC89C52RC,这个一定不能选错了;第二步,点击“打开程序文件”,找到我们刚才建立工程的那个 lesson2 文件夹,找到 LED.hex 这个文件,点击打开;第三步,选择刚才查到的
[单片机]
将程序下载到<font color='red'>单片机</font>
用于单片机系统的干扰抑制元件
  1.去耦电容   每个集成电路的电源、地之间应配置一个去耦电容,它可以滤掉来自电源的高频噪声。作为储能元件,它吸收或提供该集成电路内部三极管导通、截止引起的电流变化(di/dt),从而降低系统噪声。要选高频特性好的独石电容或瓷片电容作去耦电容。每块印制电路板电源引入的地方要安放一只大容量的储能电容。由于电解电容的缠绕式结构,其分布电感较大,对滤除高频干扰信号几乎不起作用。使用时要与去耦电容成对使用。钽电容则比电解电容效果更好。   2.抑制高频的电感   用粗漆包线穿入轴向有几个孔的铁氧体芯,就构成了高频扼制器件。将其串入电源线或地线中可阻止高频信号从电源/地线引入。这种元件特别适用于隔开一块印制电路板上的模拟电路区、数
[单片机]
用PIC单片机实现的IC卡读写器
摘要:详细介绍PIC单片机使用SPI方式与IC卡进行数据传输的原理和电路设计,以及使用USART方式与PC机进行串行异步通信的工作原理;介绍PIC单片机听SPI方式和USART方式的设置方法。 关键词:PIC单片机 IC卡读写器 SPI方式 USART方式 引言 本设计的主要目的是介绍IC卡的数据存储技术和IC卡的数据通信,因而使用存储器卡。由于本设计中既可与IC卡进行串行同步通信,又要与上位机进行中行异步通信,因而需要选择一种同时具有这两种通信方式的单片机。因为PIC16F877不仅具有本设计所需要的两种通信方式,而且还具有运行速度快、低功耗、价格低等优点,所以选择PIC16F877单片机作为本设计的单片机。 图1是本
[单片机]
ARM构架在32位微控制器领域的应用
在标准微控制器的世界中,ARM体系结构在32位嵌入式RISC领域有着极大的影响力。就像在8位世界中8051的广泛应用一样,在32位微控制器领域里ARM得到了特别的青睐,并几乎成为了事实上的标准。  对系统性能需求的提高和嵌入式功能的发展是促使设计者向32位处理器转变的一个原因;但是这种转变最大的驱动力还是来自于8位微控制器在其进化过程中自身面临的诸多局限和挑战。 虽然8位微控制器将继续领导标准产品市场,但是很多公司为了延长8位体系结构生命周期的做法,给设计工程师在开发产品时带来了越来越多的困难。8/16位解决方案的供应商近十年来以惊人的速度增加芯片上的外设、提高时钟速度并扩展架构。 这虽然提高了性能,但使设计者的工
[单片机]
8051单片机内部ROM结构、地址分布、资源利用
  51系列单片机程序存储器的管理:   每个ROM单元(byte)对应一个唯一的16bit地址编码(Address)   CPU要到某个ROM单元去取指令,是通过把地址写入一个16bit的特殊功能寄存器 程序计数器  PC(Program Counter)来实现,因此,51系列单片机的地址的编码范围(通常称为寻址范围):   0000 0000 0000 0000B ~ 1111 1111 1111 1111B(二进制)    0  0   0  0 H ~  F  F   F  F H (十六进制)         0     ~     65535    (十进制)   通常习惯说51系列单片机的ROM寻址范围
[单片机]
8051<font color='red'>单片机</font>内部ROM结构、地址分布、资源利用
MSP430FW427无磁水表设计方案详解
  1. MSP430FW42x单片机介绍   MSP430FW42x系列单片机是TI公司针对电子式流量与旋转运动检测最新开发的专用MCU芯片,它将超低功耗MCU、旋转扫描接口 (SCAN IF)和液晶显示LCD驱动模块完美地结合在一起。该器件的超低功耗结构和流量检测模块不仅延长了电池的寿命,同时还提高了仪表的精度与性能。 MSP430FW42x的典型应用包括热量仪表、热水和冷水仪表、气体仪表和工业流量计、风力计以及其他旋转检测应用。   2. 流量测量的原理   2.1 基本原理   一个由叶轮或螺旋齿轮构成的机械装置把流体流动转换为转动,这种转换能够实现对流体流量的测量。   把一个谐振回路中的电感置于叶轮的上方可以检
[单片机]
MSP430FW427无磁水表设计方案详解
以C8051F020单片机为控制核心的人机交互系统设计
在现代各类仪器的开发中,人机交互功能正起着无可替代的作用。人机交互界面友好的仪器将更容易操作和使用,从而提高工作效率。液晶显示器(LCD)具有功耗低、价格低、寿命长、接口控制方便等特点,在科研与设计领域正发挥着越来越大的作用。FPGA 作为单片机外设的接口芯片,可以大大简化接口电路,通过对FPGA 进行编程,可以实现常用的译码、地址选通等功能。 本文以C8051F020 单片机与FPGA 互连系统为控制核心,以液晶显示控制器T6963C 为例,结合行扫描键盘,简述了一种人机交互功能的设计。 1 系统设计方案: FPGA 可在很大程度上扩展单片机的资源,然而人机交互功能仍应尽量减少对单片机及FPGA 的资源消耗, 以便将更多
[单片机]
以C8051F020<font color='red'>单片机</font>为控制核心的人机交互系统设计
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved