stc89c52可自定义时间、可控制开始暂停重置时间、可报警提示的倒计时

   一、定时器设置

          首先,无论是实时时钟工程,还是倒计时工程,都离不开定时器的使用。至于定时器的调节,学过的同学肯定都会,没学过的可以看下面的步骤。

        先打开stc-isp软件。

然后找到定时器计算器,

然后开始设置定时器时间,这里需要注意几项需要调整的数据。

        当然上面的设置并不绝对,这个定时器模式的设置,我记得之前看过一篇博客,博主使用的8位自动重载模式。这里新学的萌新(当然我也是萌新)也可以直接使用我代码中的定时器设置函数,复制下来放到一个地方或者做成头文件,以便以后使用。如果有同学没有学过怎么做头文件、怎么做模块化编程的话,可以在评论区留言,我再写一篇模块化编程的教程。

        下面是我用过的一个博主的定时器设置

void DSQ_INIT()
{
	TMOD=0x11;//定时器方式
	EA=1;//开总中断
	ET0=1;//开T0中断
	TR0=0;//定时器0计时
	TF0=0;//清除TF0标志
	TH0=0x3c; //设置初值,定时时间为50ms
	TL0=0xb0;
}
 

二、时间函数(即秒数自减、分秒转换)

我们这里可以看到,设置定时器的时间是50ms,而我们需要的时间是1s,这很显然并不符合。那么怎么解决呢?很简单,让它运行20次即可。

void Timer()interrupt 1
{
	static int i=0;
	TL0 = 0xb0;		
	TH0 = 0x3c;	
 
	i++;
	if(i>19)//总共1s,因为定时器设置的是50ms,i>19,意味着20*50ms=1s
	{
		i=0;
		if(min>0||sec>0)
		{	
			if(sec==0)
			{
				sec=60;
				min--;
			}
			if(sec>0)
			{
				sec--;
			}
			
		}
	}
}

既然讲到这里了,那么顺便说一下,这个函数是一个时间控制的函数,它的效果有:使定时器运行20次,凑成1s;当秒数为0时,使秒数归为60,分钟数减一(至于为什么秒数不是变为59,而是变为60,因为我当时自己运行并烧录后发现,如果改为59的话,在秒数为0的下一秒,秒数就会变为58,很明显是下方紧接着一个“sec--”,可以看下图,由于秒数先一步变成59,所以下面的if判断几乎同时进行而非相隔1s,由此就导致造成的效果就是秒数多减了1,故我这里将秒数回归60,使秒数在0的下一秒可以变为59.);

接着上面说,圈红的地方就是这个函数的第3个功能,即秒数大于0时,秒数自减1,再结合函数运行总时间为1s,也就是每1s减秒数1,这个函数到这里就完成了。

三、数码管位选、段选(时间显示函数)

        相信既然准备做倒计时工程了,那么同学们一定学过数码管位选、段码之类了,这里便不再多说,上代码!

unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};//数码管段选,即段码


void Show_time()					
{
	P0=table[min/10%10];			//分,第一位,数码管显示数值
	LSA=0;LSB=0;LSC=1;delay(1);		//数码管位选
	
	P0=table[min%10];
	LSA=1;LSB=1;LSC=0;delay(1);
	
	P0=table[10];
	LSA=0;LSB=1;LSC=0;delay(1);
	
	P0=table[sec/10%10];			//秒,第一位
	LSA=1;LSB=0;LSC=0;delay(1);
	
	P0=table[sec%10];
	LSA=0;LSB=0;LSC=0;delay(1);
	
	P0=0x00;
}

四、倒计时自定义时间函数讲解

        由于本编程只涉及到分钟、秒钟两单位,因此只需要设置秒数加1、秒数减1、分钟数加1、分钟数减1四种调节方式即可。这一模块离不开独立按键的应用。

     1.秒数加1、减1函数

          我们都知道,按下一个独立按键,其实就相当于这个独立按键变为低电平,赋0值,比如下面:

sbit KEY4=P3^3;

void Sec_ADD()//按下K4,使秒数加1。
{
	
	
	if(KEY4==0)
	{
		delay(20);
		while(!KEY4);
			Show_time();
			sec++;
		delay(20);
		miao=sec;
			if(sec>59)
			{
				min++;
				sec=0;
				delay(20);
				fen=min;
				miao=sec;
			}
			
	}
}
 

按下KEY4按键,KEY4为0,程序运行进入if判断内,之后才可以进行之后的程序。

这里的“while(!KEY4)”,作用是,当KEY4为0时,即被按下时,陷入死循环,一直循环,直到松开,起到的作用其实就是当你的手松开的时候,它才会进行下面的程序,也就是检测你的手是否松开。

这里的程序,这个函数的作用是,按下独立按键KEY4,使秒数+1;且“if(sec>59)”这一判断的作用就是当秒数变为60时,秒数变为00;

下面是减1函数,其实逻辑上和加1函数是差不多的。

void Sec_SUB()//按下K3,使秒数减一。
{
	
	if(KEY3==0)
	{
		delay(20);
		while(!KEY3);		
			if(min>0||sec>0)
			{
				sec--;
				delay(20);
				miao=sec;
				if(sec==0&&min!=0)
				{
					min--;
					sec=59;
					delay(20);
					fen=min;
					miao=sec;				
				}
			}	
			
	}
}

这里涉及到一个语句:“sec=59”,这个语句就是当秒数为零时,再按秒数减1按键,秒数将变为59.

这里的“fen=min;miao=sec;”之类的语句,是为之后重置倒计时做准备的,“fen、miao”相当于一个暂时的储存器,重置后,将“fen、miao”中储存的数值赋给“min”和“sec”。细心的同学可能会发现,我在每一个时间调节函数里面都有这种类似的语句,就是为了能够把最新的时间储存进去。

2.终止与重置函数

具体应用看下面的函数:

void stop()//终止程序,2,3一起按下,并自己调的回归初始值
{
	
	
	if(KEY2==0)
	{
			delay(20);
			if(KEY3==0)
			{
					delay(20);
			
			while(!KEY3);
				Show_time();
				sec=miao;						//为终止程序后,倒计时回归自己调的初始值做准备。
				min=fen;
				_Delay(5000);
				P0=0xff;
				while(1)
				{
				if(KEY2==0)
				{
					delay(20);
					while(KEY2!=0);
					break;
				}
				}
			}
	}		
	
}

        这里的“sec=miao;min=fen;”语句就是将之前储存的值重新赋给“sec”和“min”,起到一个数值重置到所调节数值的作用。

        可能还会有其它更简单的方法,但是,我毕竟是萌新,只能想到通过这种中介的方法,可能相对来说会有些麻烦。

 3.暂停函数

        暂停函数相对来说不用动太多脑子,就是关闭或者说暂停定时器的计时就可以了。下面直接上个代码:

void Pause()//暂停键
{
	if(KEY2==0)
	{
		delay(10);
		if(KEY2==0)
		{
			TR0=0;
		}
	}
	if(min==0&&sec==0)
	{
		TR0=0;
		
		led=0;
	}
}

        “TR0”是控制计时器计时的,具体可以听听b站上江科大的讲解,很清晰,也易于理解。

        下面是链接: 51单片机入门教程-2020版 程序全程纯手打 从零开始入门_哔哩哔哩_bilibili

        至于计时的开始按键、开始函数,在主函数里面,最后一步会提到,慢慢来~~

4.分钟的加1、减1

        由于独立按键的数量有限,因此我这里控制分钟的函数用了两个独立按键,例如独立按键2,4同时按下,分钟加1.

        下面是代码:

void Min_ADD()//K2,K4一起按下,分钟加1;
{

	if(KEY2==0)
		{
			delay(20);
			if(KEY4==0){
			
		delay(20);
		
		while(!KEY4);
			Show_time();
			min++;
				delay(20);
				fen=min;
			}
	}
}

        这函数的解释:按下2按键后,“delay(20);”语句作用是延时消抖,然后,同时按下4,也可以一直按着2,再按4,由于是两个按键,很难完美协调,不过不影响使用,大家可以自己烧录尝试一下,就理解我说的不好协调是什么意思了>-<        ->_->。

        这里其实如果理解了分钟加1,那么分钟减1就照葫芦画瓢就可以了,我最后会发一遍完整代码,方便大家学习和调试。

 5.蜂鸣器函数

        首先需要定义上bee蜂鸣器的针脚(我习惯用来代替蜂鸣器的缩写,随便定义,不影响,方便理解就行,比如“feng、ming、di啥的”),语句是“sbit bee=P2^5;”,蜂鸣器链接的针脚是P2^5.

        蜂鸣器这一模块,如果只是单纯想让它响是很简单的,但是放音乐可能会难一些,具体学习仍旧可以看江科大视频,链接在上面,不过个人建议是网上找些代码自己学学,视频蛮长的,有些浪费时间。

        下面是代码:

void Bee()//蜂鸣器
{
	if(sec==3&&min==0||sec==2&&min==0||sec==1&&min==0)//当分钟为0,且秒为3、2、1时,蜂鸣器响
	{
		bee=~bee;
	}
}

        这里用到了“&&”,“与”的意思,其实就是“且”,语句“sec==3&&min==0”的意思就是分钟为0的同时,秒钟为3;至于“||”,是“或”的意思,那么整体意思就是,当分钟为0时,秒钟为3或2或1时,蜂鸣器响。

6.主函数(启动、运行函数)

        在这个函数中,其实就是把定时器启动计时,把之前所写的所有相关函数加进去,再设置一个启动按键就可以了。

        我这里设置的启动按键时KEY1.

//主函数
void main()
{
	
	DSQ_INIT();										//定时器
	while(1)
	{
 
		Show_time();
		
		if(KEY1==0&&(KEY3!=0))						//开始按键,即KEY1按下,倒计时开始运行。
		{
			
			if(min>0||sec>0)
			{
				TR0=1;
			}
			delay(5);
 
			while(KEY1)
			{
				Show_time();
				Pause();
				Bee();
				Sec_ADD(); 
				Sec_SUB();
				Min_SUB();
				Min_ADD();
				 stop();
			}
		}
		Pause();
		Bee();
		Sec_SUB();
		Sec_ADD(); 
		Min_SUB();
		Min_ADD();
		 stop();
    }			
}

五、完整代码

温馨提示~~会很长,毕竟函数比较多,要有耐心。

#include <REGX52.H>

unsigned char min=0;
unsigned char sec=00;
unsigned char miao;
unsigned char fen;
	
sbit KEY1=P3^1;
sbit KEY2=P3^0;
sbit KEY3=P3^2;
sbit KEY4=P3^3;
sbit LSA=P2^2;    
sbit LSB=P2^3;
sbit LSC=P2^4;
sbit bee=P2^5;
sbit led=P2^6;

sbit KEY_S5=P3^4;
unsigned char table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x40};//数码管段选,即段码
 
void delay(unsigned int z)
{
	unsigned int x,y;
	for(x=z;x>0;x--)
		for(y=114;y>0;y--);
}
 
void _Delay(int x)		//@12.000MHz
{
	while(x--)
	{
	unsigned char i, j;

	i = 12;
	j = 169;
	do
	{
		while (--j);
	} while (--i);
}
	}




void DSQ_INIT()
{
	TMOD=0x11;//定时器方式为方式一
	EA=1;//开总中断
	ET0=1;//开T0中断
	TR0=0;//定时器0计时
	TF0=0;//清除TF0标志
	TH0=0x3c; //设置初值,定时时间为50ms
	TL0=0xb0;
}
 
void Timer()interrupt 1
{
	static int i=0;
	TL0 = 0xb0;		
	TH0 = 0x3c;	
 
	i++;
	if(i>19)//总共1s,因为定时器设置的是50ms,i>19,意味着20*50ms=1s
	{
		i=0;
		if(min>0||sec>0)
		{	
			if(sec==0)
			{
				sec=60;
				min--;
			}
			if(sec>0)
			{
				sec--;
			}
			
		}
	}
}
	
void Show_time()					
{
	P0=table[min/10%10];			//分,第一位,数码管显示数值
	LSA=0;LSB=0;LSC=1;delay(1);		//数码管位选
	
	P0=table[min%10];
	LSA=1;LSB=1;LSC=0;delay(1);
	
	P0=table[10];
	LSA=0;LSB=1;LSC=0;delay(1);
	
	P0=table[sec/10%10];			//秒,第一位
	LSA=1;LSB=0;LSC=0;delay(1);
	
	P0=table[sec%10];
	LSA=0;LSB=0;LSC=0;delay(1);
	
	P0=0x00;
}
 //拓展:自定义倒计时
void Sec_ADD()//按下K4,使秒数加1。
{
	
	
	if(KEY4==0)
	{
		delay(20);
		while(!KEY4);
			Show_time();
			sec++;
		delay(20);
		miao=sec;
			if(sec>59)
			{
				min++;
				sec=0;
				delay(20);
				
			}
			
	}
}
 
 
void Sec_SUB()//按下K3,使秒数减一。
{
	
	if(KEY3==0)
	{
		delay(20);
		while(!KEY3);		
			if(min>0||sec>0)
			{
				sec--;
				delay(20);
				miao=sec;
				if(sec==0&&min!=0)
				{
					min--;
					sec=59;
					delay(20);
					fen=min;
					miao=sec;				
				}
			}	
			
	}
}
 
 
void Pause()//暂停键
{
	if(KEY2==0)
	{
		delay(10);
		if(KEY2==0)
		{
			TR0=0;
		}
	}
	if(min==0&&sec==0)
	{
		TR0=0;
		
		led=0;
	}
}
 

void Min_ADD()//K2,K4一起按下,分钟加1;
{

	if(KEY2==0)
		{
			delay(20);
			if(KEY4==0){
			
		delay(20);
		
		while(!KEY4);
			Show_time();
			min++;
				delay(20);
				fen=min;
			}
	}
}

void Min_SUB()//1,3一起按下,分钟减1;
{
	
	if(KEY1==0)
		{
			delay(20);
			if(KEY3==0){
			
		delay(20);
		
		while(!KEY3);
			Show_time();
			if(min!=0)
				{
				min--;
				delay(20);
					fen=min;
				}
				
	}
}
}

void stop()//终止程序,2,3一起按下,并自己调的回归初始值
{
	
	
	if(KEY2==0)
	{
			delay(20);
			if(KEY3==0)
			{
					delay(20);
			
			while(!KEY3);
				Show_time();
				sec=miao;						//为终止程序后,倒计时回归自己调的初始值做准备。
				min=fen;
				_Delay(5000);
				P0=0xff;
				while(1)
				{
				if(KEY2==0)
				{
					delay(20);
					while(KEY2!=0);
					break;
				}
				}
			}
	}		
	
}

//拓展:最后三秒报警提示
void Bee()//蜂鸣器
{
	if(sec==3&&min==0||sec==2&&min==0||sec==1&&min==0)//当分钟为0,且秒为3、2、1时,蜂鸣器响
	{
		bee=~bee;
	}
}
 //主函数
void main()
{
	
	DSQ_INIT();										//定时器
	while(1)
	{
 
		Show_time();
		
		if(KEY1==0&&(KEY3!=0))						//开始按键,即KEY1按下,倒计时开始运行。
		{
			
			if(min>0||sec>0)
			{
				TR0=1;
			}
			delay(5);
 
			while(KEY1)
			{
				Show_time();
				Pause();
				Bee();
				Sec_ADD(); 
				Sec_SUB();
				Min_SUB();
				Min_ADD();
				 stop();
			}
		}
		Pause();
		Bee();
		Sec_SUB();
		Sec_ADD(); 
		Min_SUB();
		Min_ADD();
		 stop();
    }			
}

六、效果视频

这个嘛,目前单片机没在手里,等我回了宿舍再更新一下文章,上传一下视频。

emmm……到宿舍了,但是我刚尝试了一下,我不会插入视频,有没有大佬教一教我。

a361923bc29c1bb6a2e639b19aece-CSDN直播

82343d698cae0c341fae11fca12985-CSDN直播

会了会了,视频链接,不晓得为啥有直播这俩字,我明明上传的视频。

七、片外话

要动手!要动手!要动手!重要的事情说三遍。

另外就是,尽量不要直接复制粘贴,那样对学习没有帮助,要尝试自己去做一做,哪怕做一个比这个简单很多的一个倒计时。

学单片机,做工程运行成功后超有成就感的好伐,我要继续学32单片机去喽~~

注:我在学这一方面时曾借鉴过一位优秀博主的编程代码:cara23456(博主名称)

Cara23456-CSDN博客(博主博客链接)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值