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

📄 4位2051闹钟.c

📁 实现小型数字钟
💻 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 DISTIME 400		//显示扫描延时量

#define Second 					0		//时钟秒单元
#define Minute 					1		//时钟分单元
#define Hour 						2		//时钟时单元
#define MinuteTiming_1 	3		//闹铃时单元
#define HourTiming_1 		4		//闹铃分单元
#define MinuteTiming_2 	5		//闹铃时单元
#define HourTiming_2 		6		//闹铃分单元

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

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

//共阴数码管0~9字符表
uchar code Disp[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x27,0x7f,0x6f};

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

//内部可寻址位定义
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=		P3^0;			//时十位驱动
sbit Hour_GWei=		P3^1;			//时个位驱动
sbit Min_SWei=		P3^2;			//分十位驱动
sbit Min_GWei=		P3^3;			//分个位驱动
sbit Timing_LED=	P3^4;			//模式指示长亮时表示闹钟功能启动
sbit Button_S1=		P3^5;			//按键S1
sbit Bee_Out=			P3^7;			//闹铃输出

//函数声明
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=0;							//关闭蜂鸣声
			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]=22;
	TimeData[Minute]=52;
	TimeData[HourTiming_1]=22;
	TimeData[MinuteTiming_1]=53;
	TimeData[HourTiming_2]=22;
	TimeData[MinuteTiming_2]=54;	
	//初始化P3口			
	P3=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[HourTiming_2]/10];
		DispData[1]=Disp[TimeData[HourTiming_2]%10]|0x80;		//加小数点以区别	
		DispData[2]=Disp[TimeData[MinuteTiming_2]/10];
		DispData[3]=Disp[TimeData[MinuteTiming_2]%10];
	}
	else
	{	
		//第1定时时间	
		DispData[0]=Disp[TimeData[HourTiming_1]/10];
		DispData[1]=Disp[TimeData[HourTiming_1]%10];	
		DispData[2]=Disp[TimeData[MinuteTiming_1]/10]|0x80;	//加小数点以区别
		DispData[3]=Disp[TimeData[MinuteTiming_1]%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(DISTIME);
	Hour_SWei=1;
	//显示时个位
	Hour_GWei=0;					
	DispOut=DispData[1];
	Delay(DISTIME);
	Hour_GWei=1;	
	//显示分十位	
	Min_SWei=0;
	DispOut=DispData[2];
	Delay(DISTIME);
	Min_SWei=1;	
	//显示分个位
	Min_GWei=0;
	DispOut=DispData[3];
	Delay(DISTIME);
	Min_GWei=1;				
}

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

//函数功能:启动闹铃输出
void StartBuzze(void)
{
	TimingSuitedFlag=1;
	ET1=1;
	TR1=1;										//用TR1控制闹铃声响	
}	
	
//按键扫描函数:产生键值
void KeyScan(void)
{	
	uint KeyLongTime;
	
	if(!Button_S1)						
	{
		//启动按键声
		Bee_Out=1;																
		//有闹铃输出时		
		if(TimingSuitedFlag)				
		{
			TimingSuitedFlag=0;
			Bee_Out=0;								//闹铃停闹
			TR1=0;										//关闭TR1
			ET1=0;			
		}				
		else
		{															
			while(!Button_S1)					//等待按键松开
			{
				KeyLongTime++;					//长按键计时开始
				if(KeyLongTime>300)
				{
					Bee_Out=0;						//关闭按键声
					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[HourTiming_1];	//指针指向时间单元
			ChangeData(j);							//调用增量函数改变时间值
			break;
		//第5次按键分数跳变(闹铃模式)
		case 5:
			j=&TimeData[MinuteTiming_1];
			ChangeData(j);
			break;
		//第6次按键等待确认
		case 6:
			UnpressKeyTimeFlag=1;						//启动无按键计时
			break;
		//第7次按进入第2定时时间设置
		case 7:
			TimingDisSelectFlag=1;
			break;
		//
		case 8:
			UnpressKeyTimeFlag=0;
			j=&TimeData[HourTiming_2];	//指针指向时间单元
			ChangeData(j);							//调用增量函数改变时间值
			break;
		//第9次按键分数跳变(闹铃模式)
		case 9:
			j=&TimeData[MinuteTiming_2];
			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 
{
	uchar 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 + -