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

📄 2051.c

📁 基于STC89C2051单片机的电子钟
💻 C
字号:
			  //目标器件AT89C2051晶振12M
//单键操作实现校时和每天任意两个时间点定闹

//在有闹铃响时按键则停闹
//在正常模式时按键则开启或关闭闹铃功能

//查看闹铃时间:在正常模式时第1次按键显示第1闹铃时间,第2次按键显示第2闹铃时间,3秒后返回正常模式

//设置闹铃时间:在正常模式时在3秒内连按3次键进入闹钟设定模式,此时若不按键5秒后返回正常模式
//继续按键则时数跳变,再按键分数跳变,再按键完成第1闹铃时间设置等待确认
//继续按键则进入第2闹铃时间设置否则5秒后返回正常模式

//设置时钟时间:在正常模式时长按键5秒则进入校时模式,设置过程与闹铃模式相似,设置完成后返回正常模式
//2008年10月12日	I2C

//头文件包含
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
#define CYCLE0 50240	//每隔CYCLE0微秒T0产生中断
#define CYCLE1 20000	//每隔CYCLE1微秒T1产生中断
#define num 400		//显示扫描延时量

#define Second      	0		//时钟秒单元
#define Minute      	1		//时钟分单元
#define Hour 		    2		//时钟时单元
#define Minute_n1 	3		//闹铃时单元
#define Hour_n1 	4		//闹铃分单元
#define Minute_n2 	5		//闹铃时单元
#define Hour_n2 	6		//闹铃分单元

#define DispOut		P3			//字符码由P3输出
//#define DisScan		P1			//位扫描码由P1输出

//数据缓冲区
uchar TimeData[7];				//时间数据缓冲区
uchar DispData[4];				//显示缓冲区

//共阳数码管0~9字符表
uchar code Disp[10]={0xc0,0xf9,0x64,0x70,0x59,0x52,0x42,0xf8,0x40,0x50};

//全局变量定义
uchar KeyVal,f;					//键值单元

//内部可寻址位定义
bit SecondFlag;						//时钟秒信号位
bit SecondFlashFlag;				//时钟秒闪信号位
bit AddFlag;						//设定模式增量信号位

bit TimeSetFlag;					//校时模式标志位
bit TimingSetFlag;					//闹铃模式标志位
bit SetModeFlag;					//设置模式标志位

bit TimingFunFlag;					//闹铃功能的标志位
bit TimingSuitedFlag;				//闹铃时间匹配标志位
bit BeeNopFlag;						//闹铃输出反相信号位
bit BeeMusicFlag;					//闹铃声次数信号位
bit BeeSpaceFlag;					//闹铃声间隔信号位
bit TimingDisSelectFlag;		    //闹铃时间显示选取择控制位

bit KeyTimeOutFlag;					//连续击键超时计数控制位
bit UnpressKeyTimeFlag;		    	//无按键计时控制位

//输出连接定义
sbit Hour_SWei=		P1^5;			//时十位驱动
sbit Hour_GWei=		P1^4;			//时个位驱动
sbit Min_SWei=		P1^3;			//分十位驱动
sbit Min_GWei=		P1^2;			//分个位驱动
//sbit Timing_LED=	P3^4;			//模式指示长亮时表示闹钟功能启动
sbit Button_S1=		P1^7;			//按键S1
sbit Bee_Out=	   P1^6;			//闹铃输出

//函数声明
void Delay(uint i);					//延时函数
void System_init(void);			//系统初始化函数
void TimerMake(void);				//计时函数
void Display(void);					//显示函数
void KeyScan(void);					//键值产生函数
void KeyFunction(void);			//键功能处理函数
void TimeCompate(void);			//时间比较函数
void ChangeData(uchar *x);	    //设置模式自动增量函数
void TimeDisData(void);			//时钟数据显示处理函数
void TimingDisData(void);		//闹铃数据显示处理函数
void ClearFlag(void);
void StartBuzze(void);
void T0_intermit(void);			//T0中断函数
void T1_intermit(void);			//T1中断函数

//主函数
void main(void)
{
	uchar DispScanTime;
	uchar KeyTimeOut;
	uchar UnpressKeyTime;	
	
	System_init();
	
	while(1)
	{
		DispScanTime++;
		//显示扫描
		if(DispScanTime%25==0)	
			Display();						
		//键盘扫描
		if(DispScanTime>250)
		{
			DispScanTime=0;
			Bee_Out=1;				//关闭蜂鸣声
			KeyScan();
			KeyFunction();
		}
		//计时
		if(SecondFlag)
		{
			SecondFlag=0;
			//时钟计时
			TimerMake();
			//连续击键超时计时
			if(KeyTimeOutFlag)
			{
				if(++KeyTimeOut>=3)
					ClearFlag();		//返回正常模式
			}
			else
				KeyTimeOut=0;
			//无按键计时			
			if(UnpressKeyTimeFlag)
			{
				if(++UnpressKeyTime>=5)
					ClearFlag();			
			}
			else
				UnpressKeyTime=0;				
		}		
		//闹铃启动
		if(TimingFunFlag&&!SetModeFlag&&!TimingSuitedFlag)
		{
			TimeCompate();	    	//时间比较
		//	Timing_LED=0;			//LED亮表示闹铃功能生效													
		}					//声光闹铃输出
		else if(TimingSuitedFlag&&BeeSpaceFlag)
		{
			BeeNopFlag=BeeMusicFlag;
			Bee_Out=!BeeNopFlag;				//取反再输出			
		//	Timing_LED=!BeeSpaceFlag;		//闹铃输出时LED闪烁
		}
	//	else	
		//	Timing_LED=1;															
	}
}

//初始化函数
void System_init(void)
{
	//置显示初值
	TimeData[Hour]=12;		   //时间初值
	TimeData[Minute]=58;

	TimeData[Hour_n1]=6;	   //第一组闹铃初值
	TimeData[Minute_n1]=36;

	TimeData[Hour_n2]=7;	   //第二组闹铃初值
	TimeData[Minute_n2]=15;	
	//初始化P3口			
	P1=0xff;
	//设T0,T1为方式1								
	TMOD=0x11;              
	//装T0初值
	TH0=(-CYCLE0)/256;
	TL0=(-CYCLE0)%256;
	//装T1初值
	TH1=(-CYCLE1)/256;
	TL1=(-CYCLE1)%256;						
	//开中断及启动T0
	EA =1;
	ET0=1;
	TR0=1;              
}

//延时函数
void Delay(uint i)
{
	while(i--);
}

//函数功能:时钟计时
void TimerMake(void)
{			
	if(++TimeData[Second]>=60)		  //秒
	{
		TimeData[Second]=0;
		if(++TimeData[Minute]>=60)	  //分
		{
			TimeData[Minute]=0;	
    	if(++TimeData[Hour]>=24)	  //时
    		TimeData[Hour]=0;
		}
	}
}

//时钟显示数据放入显示缓冲区
void TimeDisData(void)
{
	DispData[0]=Disp[TimeData[Hour]/10];
	if(SecondFlashFlag)
	{	
		//每半秒加小数点用于秒闪
//		DispData[1]=Disp[TimeData[Hour]%10]|0x80;	
//		DispData[2]=Disp[TimeData[Minute]/10]|0x80;
//	}
//	else
//	{	
		DispData[1]=Disp[TimeData[Hour]%10];	
		DispData[2]=Disp[TimeData[Minute]/10];
	}	
    	DispData[3]=Disp[TimeData[Minute]%10];
}
	//闹铃显示数据放入显示缓冲区
void TimingDisData(void)
{
	if(TimingDisSelectFlag)
	{
		//第2定时时间
		DispData[0]=Disp[TimeData[Hour_n2]/10];
		DispData[1]=Disp[TimeData[Hour_n2]%10]; 	
		DispData[2]=Disp[TimeData[Minute_n2]/10];
		DispData[3]=Disp[TimeData[Minute_n2]%10];
	}
	else
	{	
		//第1定时时间	
		DispData[0]=Disp[TimeData[Hour_n1]/10];
		DispData[1]=Disp[TimeData[Hour_n1]%10];	
		DispData[2]=Disp[TimeData[Minute_n1]/10];	
		DispData[3]=Disp[TimeData[Minute_n1]%10];
	}	
}
			
//函数功能:显示
//两种显示程序都可行,生成的代码量相当
void Display(void)
{
/*	uchar i;
	uchar databat;
	uchar ScanStart=0x0e;			//扫描初值,由低位开始扫描

	//选择显示数据
	if(TimingSetFlag)
		TimingDisData();
	else
		TimeDisData();
	//动态扫描显示
	for(i=0;i<4;i++)
	{	
		databat=DisScan&0xf0;				//保存P3口当前状态	
		DisScan=databat|0x2f;				//清屏		
		DispOut=DispData[i];				//输出字符码
		DisScan=databat|(ScanStart&0x2f);		//输出位扫描码
		Delay(DISTIME);											//延时
		ScanStart=(ScanStart<<1)+1;					//产生下一位扫描码		
	}*/

	//选择显示数据
	if(TimingSetFlag)
		TimingDisData();
	else
		TimeDisData();		
	//显示时十位	
	Hour_SWei=0;		
	DispOut=DispData[0];
	Delay(num);
	Hour_SWei=1;
	//显示时个位
	Hour_GWei=0;					
	DispOut=DispData[1];
	Delay(num);
	Hour_GWei=1;	
	//显示分十位	
	Min_SWei=0;
	DispOut=DispData[2];
	Delay(num);
	Min_SWei=1;	
	//显示分个位
	Min_GWei=0;
	DispOut=DispData[3];
	Delay(num);
	Min_GWei=1;				
}

//函数功能:定闹时间比较
void TimeCompate(void)
{
	//时分相等且秒为0时启动闹铃输出	
	if(TimeData[Second]==0)
	{
		if((TimeData[Hour_n1]==TimeData[Hour])&&(TimeData[Minute_n1]==TimeData[Minute]))
			StartBuzze();
					else if((TimeData[Hour_n2]==TimeData[Hour])&&(TimeData[Minute_n2]==TimeData[Minute]))
			StartBuzze();
	}						
}

//函数功能:启动闹铃输出
void StartBuzze(void)
{
	TimingSuitedFlag=1;
	ET1=1;
	TR1=1;							//用TR1控制闹铃声响	
}	
	
//按键扫描函数:产生键值
void KeyScan(void)
{	
	uint KeyLongTime;
	
	if(!Button_S1)						
	{		
		Bee_Out=0;				    	//启动按键声														
		if(TimingSuitedFlag)			//有闹铃输出时	
		{
			TimingSuitedFlag=0;
			Bee_Out=1;					//闹铃停闹
			TR1=0;						//关闭TR1
			ET1=0;			
		}				
		else
		{															
			while(!Button_S1)				//等待按键松开
			{
				KeyLongTime++;				//长按键计时开始
				if(KeyLongTime>300)
				{
					Bee_Out=1;				//关闭按键声
					Display();				//保持显示
				}				
				if(KeyLongTime>600)			//长按键超过5秒
				{
					TimeSetFlag=1;			//进入校时模式										
					SecondFlashFlag=1;		//使秒闪长亮					
					KeyVal=12;				//键值置12指向校时模式起始键值					
				}							//校时设定模式的后续键值由KeyVal++产生
			}
			//按键松开
			KeyVal++;						//产生键值
			KeyLongTime=0;					//清长按键计时
			TimingFunFlag=!TimingFunFlag;	//闹铃功能开或关			
		}								
	}	
}//键功能函数:执行键值功能
void KeyFunction(void)
{
	uchar *j;								//定义指针
				switch(KeyVal)
	{
		//第1次按键
		case 1:
			KeyTimeOutFlag=1;				//启动按键超时计数
			TimingSetFlag=1;
			break;
		//第2次按键
		case 2:
			TimingDisSelectFlag=1;			//显示第2定时时间
			TimingFunFlag=1;
			break;
		//第3次按键进入闹铃模式	
		case 3:
			KeyTimeOutFlag=0;				//关闭按键超时计数
			TimingSetFlag=1;				//进入闹铃设置模式
			TimingDisSelectFlag=0;
			UnpressKeyTimeFlag=1;			//启动无按键计时
			SetModeFlag=1;
			break;			
		//第4次按键时数跳变(闹铃模式)
		case 4:
			UnpressKeyTimeFlag=0;
			j=&TimeData[Hour_n1];	//指针指向时间单元
			ChangeData(j);				//调用增量函数改变时间值
			break;
		//第5次按键分数跳变(闹铃模式)
		case 5:
			j=&TimeData[Minute_n1];
			ChangeData(j);
			break;
		//第6次按键等待确认
		case 6:
			UnpressKeyTimeFlag=1;			//启动无按键计时
			break;
		//第7次按进入第2定时时间设置
		case 7:
			TimingDisSelectFlag=1;
			break;
		//
		case 8:
			UnpressKeyTimeFlag=0;
			j=&TimeData[Hour_n2];	//指针指向时间单元
			ChangeData(j);				//调用增量函数改变时间值
			break;
		//第9次按键分数跳变(闹铃模式)
		case 9:
			j=&TimeData[Minute_n2];
			ChangeData(j);
			break;
		//
		case 10:
			UnpressKeyTimeFlag=1;		//启动无按键计时
			break;			
		//第11次按键完成并返回正常模式	
		case 11:
			ClearFlag();					
			break;
		//	
		case 12:				
			break;
		//长按键后键值=13进入校时模式
		case 13:
			SetModeFlag=1;				
			break;					
		//校时模式第1次按键时数跳变									
		case 14:
			j=&TimeData[Hour];
			ChangeData(j);
			break;
		//校时模式第2次按键分数跳变
		case 15:
			j=&TimeData[Minute];
			ChangeData(j);
			break;
		//校时模式第3次按键等待对时
		case 16:
			TimeData[Second]=0;
			break;			
		//校时模式第4次按键完成并返回正常模式
		case 17:
			TimeSetFlag=0;
			SetModeFlag=0;
			KeyVal=0;
			break;						
		default:
			break;						
	}
}

//函数功能:设置模式时自动增量改变所设项目
void ChangeData(uchar *x)
{		
	uchar i;

	i=*x;							//取出数据
				
	if(AddFlag)						//检测半秒增量标志位
	{
		AddFlag=0;
		if((KeyVal==4)||(KeyVal==8)||(KeyVal==14))
		{
			if(++i>=24)				//时数增加
				i=0;
		}
		else if(++i>=60)		//分数增加
			i=0;				
	}
	*x=i;							//保存数据}	

//函数功能:清各个相关控制位返回正常模式
void ClearFlag(void)
{
	UnpressKeyTimeFlag=0;
	KeyTimeOutFlag=0;
	SetModeFlag=0;
	TimingSetFlag=0;
	TimingDisSelectFlag=0;
	KeyVal=0;							//返回正常模式	
}
		//函数功能:T0中断服务子程序(产生秒脉冲等)

void T0_intermit(void) interrupt 1 
{
	uint TimeT0;

	TH0=(-CYCLE0)/256;
	TL0=(-CYCLE0)%256;
	
	TimeT0++;
		
	if(TimeT0%10==0)
	{
		AddFlag=1;				//设置模式的增量标志位置1
		if(!TimeSetFlag)
			SecondFlashFlag=!SecondFlashFlag;	//秒闪脉冲
	}
			if(TimeT0>=20)			//累计20次为1秒
	{
		TimeT0=0;
		if(!TimeSetFlag)
			SecondFlag=1;		//秒位置1
	}
}
//函数功能:T1中断服务子程序(产生闹铃声响)
//产生宽度为100ms和600ms的方波
void T1_intermit(void) interrupt 3 
{
	uchar TimeT1;
				
	TH1=(-CYCLE1)/256;
	TL1=(-CYCLE1)%256;
	
	TimeT1++;
	
	if(TimeT1%5==0)
		BeeMusicFlag=!BeeMusicFlag;		//100ms
		
	if(TimeT1>=30)
	{
		TimeT1=0;
		BeeSpaceFlag=!BeeSpaceFlag;		//600ms
	}		
}

⌨️ 快捷键说明

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