新手学单片坤之定时器

本文详细介绍了新手如何在Proteus和普中单片机板上使用定时器控制LED灯,以及通过计数器中断实现按钮操作控制LED闪烁。文章强调了中断函数中避免耗时代码的重要性,并提供了不同实验的代码示例和仿真效果。
摘要由CSDN通过智能技术生成

新手学单片坤之定时器

一、Proteus和普中单片机板上分别完成采用定时计数器控制LED灯每隔1s周期性亮灭的实验

代码1

``#include <REGX52.H>`

void Timer0Init()//1毫秒@12.000MHz
{
//TMOD=0x01; //0000 0001,特殊功能寄存器里,通过赋值选择定时器工作模式
TMOD&=0xF0;//把TMOD低四位清零,高四位保持不变
TMOD|=0x01;//把TMOD最低位置一,高四位保持不变
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值,通过STC软件给的延时
// TH0=64535/256;自己计算的延时
// TL0=64535%256;

TF0=0;

TR0=1;

ET0=1;
EA=1;
PT0=0;
}

void main()
{
Timer0Init();
while(1)
{

}

}

void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC;
T0Count++;
if(T0Count>=1000)
{
T0Count=0;
P2_0=~P2_0;
}

}

**代码具体解释1:**也可以观看B站江协进行理解

1、从main函数进入,调用Timer0Init()函数

2、TMOD=某个16位二进制数,就是选择定时器工作模式,因为定时器有不止一个工作模式,在此次实验中,我们选择模式1,并且只用到了定时器0

请添加图片描述
请添加图片描述

如上图,模式1是16位,所以我们在选择时就将TMOD=0x01,至于TMOD&=0xF0;TMOD|=0x01;是为了防止我们在同时使用定时器1和0的时候刷新定时器1的状态,但本次实验只用到了定时器0,所以采用第一种方式也是可以的。

3、TL0 = 0x18;TH0 = 0xFC;,从模式1中我们找到这一模块,这模块就相当于是定时模块,每个1us加1,总共16位,所以范围就是0~65535。这里我们分别给低八位和高八位赋值。我们先将1ms的时间计算出来,就能够得到从64535直到65535就是1ms。通过上面的代码注释可以看见我们使用的是软件给的数。如果需要我们自己去计算的话,就是用65535除256取整得到高八位的数,取余得到低八位的数。为什么是256,因为八位二进制最大就是255。所以我们也可以用自己计算的数去得到1ms的延时。

4、TF0=0;

TR0=1;请添加图片描述
这个先记住这么写就行,也可以看上图去理解。

5、ET0=1;
EA=1;
PT0=0;
请添加图片描述

上图是中断结构,我们此次用的是T0计时器,所以把ET0置1,EA置一,PT0默认是置0,也可以不写。

至此定时器部分就介绍完了。

6、由于定时器是自己呆在一边计时,所以当定时器记满时就会触发中断溢出标志位,然后跳转到中断程序

什么是中断:中断即打断,实至CPU再执行当前程序时,由于系统出现了某种需要处理的紧急情况,CPU暂停正在执行的程序,转而去执行另一段特殊程序来处理的出现的紧急事务,处理结束后CPU自动返回到原先暂停的程序中去继续执行,这种执行过程由于外界的的原因被中间打断的情况成为中断

void Timer0_Routine() interrupt 1 这就是中断函数,具体的函数内容根据项目要求来设置。其中 interrupt

是中断函数的固定写法。”1“是代表了中断号,你使用哪一个中断源就要用对应的中断号。下图是51中常见的中断源。

请添加图片描述

7、static unsigned int T0Count;设置一个静态变量

8、TL0 = 0x18;
TH0 = 0xFC; 又给定时器赋初值,因为当定时器溢出的时候会重新从0开始每1us加1。所以就需要给他再次赋初值,让定时器固定1ms进入中断。

9、 T0Count++;
if(T0Count>=1000)
{
T0Count=0;
P2_0=~P2_0;
}

}如果进入中断, T0Count++;就++,直到大于等于1000,这样就相当于定时器循环了1000次1us,加起来就是1s,就能达到我们想要的效果。然后又将 T0Count++;变为0,重新开始加。led就重复亮灭。

Proteus仿真效果

请添加图片描述

开发板实验图

请添加图片描述

Keil中logic图

请添加图片描述

可以看出周期正好是1s。

二、采用计数器中断,实现 按4次按钮开关后,P2口的8只LED闪烁不停。

代码2

#include <REGX52.H>

void Delay(unsigned int i)	
	{
		unsigned int j;		
  for(;i>0;i--)			//变量i由实际参数传入一个值					//因此i不能赋初值
  for(j=0;j<125;j++)		
  {;}		
			
	}

void main()
{
//主函数

TMOD=0x05;			//设置定时器T0为方式1计数
TH0=0xff;			//向TH0写入初值的高8位
TL0=0xfc;			//向TL0写入初值的低8位
EA=1;    				//总中断允许

ET0=1; //定时器T0中断允许 TR0=1;

  while(1)

{

}

}
void T0_int(void) interrupt 1 //T0中断函数
{
for(;;) //无限循环
{
P2=0xff; //8位LED全灭
Delay(500) ; //延时500ms
P2=0; //8位LED全亮
Delay(500); //延时500ms
}
}

代码解释2

主要解释一下TMOD=0x05;这段代码就是二进制0000 0101,对应TOMD的功能可以看上图。当C/T等于1时就可以通过外部引脚计数了。

仿真效果如下

请添加图片描述

由于没有买额外的按键,所以就没有开发板效果图了

三、中断函数中要尽量避免使用执行时间较长(耗时)的代码,以避免中断服务影响到主程序代码的执行效率。但是在上面外部中断的实验中,中断函数采用了软件延时函数去控制LED亮灭的间隔周期。这是一种不好的编程。请你思考,换一种更合理的方式,不在中断函数使用延时循环,实现同样的功能。

可见本次实验中的第一个代码,并没有像第二个代码那样在中断函数中调用延时函数。

四、外部中断控制流水灯

代码3

#include <REGX52.H>
void Delay(unsigned int i)	//延时函数Delay( ),i形式参数,不能赋初值`
{
unsigned int j;
for(;i > 0;i--)	
for(j=0;j<333;j++)         //晶振为12MHz,j选择与晶振频率有关`
{;}			   //空函数
}

void  main()			//主函数`
{
EA=1;//总中断允许`
EX0=1;//允许外部中断0中断`
IT0=1;	
while(1){};//循环`		
}

void int0( )  interrupt 0  	//外中断0的中断服务函数`
{
static unsigned int count;
count++;
if(count==1)
{Delay(100);
	P2_7=1;
	Delay(100);
	P2_0=0;
}
if(count==2)
{
	Delay(100);
	P2_0=1;
  Delay(100);
  P2_1=0;
}

if(count==3)
{
	 Delay(100);
  P2_1=1;
  Delay(100);
  P2_2=0;
}
	if(count==4)
{
	 Delay(100);
  P2_2=1;
  Delay(100);
  P2_3=0;
}
	if(count==5)
{
	 Delay(100);
  P2_3=1;
  Delay(100);
  P2_4=0;
}
	if(count==6)
{
	 Delay(100);
  P2_4=1;
  Delay(100);
  P2_5=0;
}
	if(count==7)
{
	 Delay(100);
  P2_5=1;
  Delay(100);
  P2_6=0;
}
	if(count==8)
{
	 Delay(100);
  P2_6=1;
  Delay(100);
  P2_7=0;
	count=0;
}
}

代码较为简单死板就不做过多解释了,其中给管脚赋值还可以用位移符号来实现,当时没想这么多,哈哈。

一旦我们按下外部中断就INT0,就进入中断程序,然后判断count的值,再进入对应的语句,然后再退出中断,如此往复。

Proteus仿真效果

请添加图片描述

代码较为简单死板就不做过多解释了,其中给管脚赋值还可以用位移符号来实现,当时没想这么多,哈哈。

一旦我们按下外部中断就INT0,就进入中断程序,然后判断count的值,再进入对应的语句,然后再退出中断,如此往复。

五、总结:

了解了定时器与中断的使用,感觉定时器更为复杂,因为定时器也需要用到中断,哈哈。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值