⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clock.c

📁 电子中开发程序 有图
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <AT89x51.h>
#include "intrins.h"
unsigned char hour,min,sec,year,month,day,weekday;   //当前时间?日期?星期
unsigned int  count_down;       //1秒钟计时用
bit led_on;                      //数码管是否点亮的标志
unsigned char display[8];       //8位数码管要显示的数据
unsigned char attr;             //八个数码管的闪烁控制字节,当为0时,对应数码管闪
bit flash;                       //LED 闪烁开关,与attr共同决定数码管是否闪烁
unsigned char show_status;      //LED 显示状态标志
	// 0:设置闹钟数据
	// 1:显示当前日期及星期
	// 2:显示当前时间
	// 3:设置当前日期
	// 4:设置当前时间
bit km;                          //按键已去抖动标志
bit kp;                          //按键已处理标志
bit sound;                       //蜂鸣器响标志
bit alarm_stop;                  //蜂鸣器响后用户手工按停标志
struct  { 	unsigned char h;    //小时
       		unsigned char m;  	 //分钟
         } alarm[8];             //定义结构数组,8个闹钟项
unsigned char alarm_en;         //闹钟项启用标志
unsigned char alarm_wk;         //闹钟项周末启用标志
unsigned char cur_alarm_set;    //当前设置的闹钟项
unsigned char cur_alarm_active; //当前到点的闹钟项
bit new_alarm_info;              //闹钟项内容已修改标志
sbit sound_output = P1^5;        //蜂鸣器驱动端口,输出0时蜂鸣器响
sbit SDA   = P1^6;     			  //EEPROM数据线端口
sbit SCL   = P1^7;    			  //EEPROM时钟线端口


//以下是EEPROM操作时需要的延时函数
void I2cDelay() 
{
	_nop_();  _nop_();  _nop_();
    _nop_();  _nop_();  _nop_(); 
}

//以下是延迟函数,参数为毫秒数
void DelayX1ms(unsigned char count) 
{
	unsigned char i,j;
    for(i=0;i<count;i++)
    for(j=0;j<240;j++)   ;
}

//以下是I2C启动函数,24C08使用I2C方式
void Start() 
{
	SDA=1; 
	I2cDelay(); 
	SCL=1; 
	I2cDelay();
	SDA=0; 
	I2cDelay();  
	SCL=0;  
} 

//以下是I2C停止函数
void Stop()
{ 
	I2cDelay();
	SDA=0;
	I2cDelay();
	SCL=1; 
	I2cDelay(); 
	SDA=1; 
	I2cDelay();
}

//以下是发送1字节数据给EEPROM函数
bit SendByte(unsigned char value)
{
	unsigned char i;
	bit no_ack=0;
	for(i=0;i<8;i++)     //发送8位数据
	{
		I2cDelay(); 
		if(value&0x80)   SDA=1;
		else             SDA=0;
		value=value<<1;
		I2cDelay();
		SCL=1; 
		I2cDelay();
		I2cDelay(); 
		SCL=0; 
	}
	I2cDelay(); 
	SDA=1;     //确认脉冲周期,等待EEPROM的确认
	I2cDelay();
	SCL=1; 
	I2cDelay();
	if(SDA==1)   no_ack=1;
	I2cDelay(); 
	SCL=0;
	return no_ack;
}

//以下是向EEPROM写1字节函数
void mywrite(unsigned char address,unsigned char value) 
{
	Start();
	SendByte(0xa0);      //发送从地址
	SendByte(address);   //发送子地址
	SendByte(value);     //发送数值
	Stop();
	DelayX1ms(10);
}

//以下是从EEPROM接收1字节函数
unsigned char ReadByte()
{
	unsigned char i,bval;
	bval=0;
	for(i=0;i<8;i++)        //接收8位数据
	{
		I2cDelay();
		SDA=1;              //从P1输入数据时,先往P1输入"1"
		I2cDelay();
		SCL=1;
		I2cDelay();
		bval=bval<<1; 
		if(SDA)    bval=bval|0x01;
		I2cDelay();
		SCL=0;
	}
	I2cDelay(); 
	SDA=1;  //确认脉冲周期,不送出确认
	I2cDelay();
	SCL=1; 
	I2cDelay(); 
	I2cDelay();
	return(bval);
}
//以下是从EEPROM读入1字节数据函数
unsigned char myread(unsigned char address) 
{
	unsigned char tmp;
	Start();
	SendByte(0xa0); 
	SendByte(address); 
	Start();
	SendByte(0xa1);
	tmp=ReadByte();
	Stop();
	DelayX1ms(2);
	return(tmp);
}


//以下是定时器0中断程序,用于走时,1/8000秒一次
void Timer0ISR(void) interrupt 1 using 3 
{
	unsigned char tmp; unsigned int tmp_days;
	P3=~P3;
	count_down--;
	if(count_down==1 || count_down==1001 || count_down==2001 || count_down==3001)
	{
		flash=~flash;                //数码管闪烁的开关量
		if(sound && flash)
	    sound_output=0;  			 //驱动蜂鸣器
		else  sound_output=1;        //关闭蜂鸣器
		return;
	}
/*** 计算当前日期为星期几***/ 
 if(count_down==1500)
{
	if(year==0)       weekday=5;    //2000年1月1日为星期六
	else { 
			tmp=(year-1)/4+1;
	  		tmp=(year-tmp)+tmp*2;
			weekday=(tmp+5)%7;
		  }      //计算出当前年的1月1日为星期几

	tmp_days=0;
	for(tmp=1;tmp<month;tmp++)
	if(tmp==1 || tmp==3 || tmp==5 || tmp==7 || tmp==8 || tmp==10 || tmp==12)
	tmp_days=tmp_days+31;
	else if(tmp==4 || tmp==6 || tmp==9 || tmp==11)
	tmp_days=tmp_days+30;
	else if(tmp==2)
	{
		if(year%4==0) tmp_days=tmp_days+29;
		else   tmp_days=tmp_days+28;
	}
	tmp_days=tmp_days+day-1; 
	weekday=(weekday+tmp_days%7)%7+1;
	return;
}

 /***  查询是否有闹钟时间项符合触发条件 ***/
if(count_down==2500)
{
	if((alarm_stop || sound) && alarm[cur_alarm_active].m!=min)  //触发后1分钟
	{
		alarm_stop=0; 
		sound=0;
    }       //自动关蜂鸣器
 	if(sound==0 && alarm_stop==0)           //没有已触发的闹钟项
	for(tmp=0;tmp<8;tmp++)   			    //则查询8个闹钟项内是否有符合条件的
	{
	if(((alarm_en>>tmp)&1)==0) continue;   //该闹钟项不启用
	if(((alarm_wk>>tmp)&1)==1)              //该闹钟项周末有效
 	{
		if(weekday!=6 && weekday!=7) continue;
	}//不是星期六或星期天
	else
	{ 
		if(weekday==6 || weekday==7) continue;
	}
 	if(alarm[tmp].h==hour && alarm[tmp].m==min) //比较当前时间
	{ 
		sound=1;  cur_alarm_active=tmp; break; 
	}  //与该闹钟项的时间
 }
 return;
}
	if(count_down==0)      //过了一秒钟
	{ 
		count_down=4000;
		sec++;
		if(sec==60)
		{
			sec=0;
			min++;
		 	if(min==60)
			{
				min=0; hour++;
		 		if(hour==24)
				{
					hour=0; 
					day++;
					switch(day)
 					{
						case 29: if(month==2 && year%4)    
								 { 
								 	day=1; 
									month=3; 
								  } break; 
						case 30: if(month==2 && year%4==0) 
						         { 
								 	day=1; 
									month=3; 
								 } break; 
						case 31:if(month==4 || month==6 || month==9 || month==11)  
								 { 
								 	day=1; 
									month++; 
								 } break; 
 						case 32: day=1;   month++;
								if(month==13) 
								{ 
									month=1; 
									year++; 
								}
					}
				}
			}
		}
	}
}


//以下是定时器2中断,用于按键扫描
void Timer1ISR(void) interrupt 3 using 2 
{
	unsigned char keytmp;
	char tmp;
	TH1=0x15; TL1=0xa0;      // 每30ms中断一次
/***  当前显示的内容 ***/
	if(show_status==0)   //当前正在设置闹钟项
	{
		display[0]=cur_alarm_set;
		display[1]=0xf;
		display[2]=alarm[cur_alarm_set].h/10;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -