徐晓峰
2021.4.27

51单片机给我们提供了2个计时器中断,分别是计时器0和计时器1,他们对应的优先级分别是1和3,开启计时器并允许其中断后,计时器会从给定的初始值开始,每个指令周期加1,直到加到65535,再加一时计时器溢出,计时器此时会进入中断,并执行中断服务函数。

  • 虽然书上讲的很清楚了,但实际使用还是有些许差别,我自己是这样理解的

65536-50000的由来

  • 假设我使用的单片机的晶振为12MHZ,其机器周期是1us,即每1us产生一次计数
  • 如果设计一个1s的定时器,理论上是需要1*10^6个机器周期,但定时器T0只能对机器周期能进行最大65536次计数,很明显已经超过了,并不能直接采用T0的默认值
  • 转下思维模式,取个65535之内的整数值,经过简单倍数关系即可转换为1s。很明显,50ms符合要求。即一次中断5 * 104次,中断20次即为1s
  • 但根据中断原理,T0中断器溢出时计数1次,但5 * 104<65536,根本不会发生溢出。此时有需要转下思维模式,如果我给T0定时器附上初始值,使其从初试值开始计数,最终读数为65536发生溢出,中断一次。这个初始值就是65536和5 * 104的差值

/256 和 %256 的由来

  • T0中断器由两个8位构成,低8位,即28,满打满算也只能计数256个机械周期,当大于256个机械周期就必须采用高8位了。换而言之,高8位每增加1,低八位就装满一次。
  • 故用初始值除以256取整,存入高8位。取余,即小于256次数,放入低8位。
TH0=(65536-50000)/256; 	     // (65536-50000)/256=60.6875
TL0=(65536-50000)%256;      
  • 这就是这两句话的由来

以下附上C51程序代码

#include<reg51.h>
#include<intrins.h>	
int flag=0;
sbit LED = P2^0;
void main()
{
	TMOD=0x10;          //工作于方式1
	//0 0 方式0 13位计数器 TMOD=0x00
	//0 1 方式1 16位计数器 TMOD=0x01
	//1 0 方式2 自动重装8位计数器 TMOD=0x02
	//1 1 方式3 T0分为2个8位独立计数器,T1为无中断重装8位计数器 TMOD=0x03
    EA=1;              // 中断允许
    ET1=1;						 // 中断1打开
	TH1=(65536-50000)/256; 	     // (65536-50000)/256=60.6875
	TL1=(65536-50000)%256;      
	TR1=1;
    while(1){}
}
void timer1(void) interrupt 3
{ 
  TH1=(65536-50000)/256;
	TL1=(65536-50000)%256;
  flag++;
	if (flag==20)	     //达到1s
		{
			flag	=0;
			LED=~LED;
		}	  			
}


实验原理图

  • 很简单,只是在P2^0口加入了LED灯

    在这里插入图片描述

拓展一下

如果要求做成流水灯呢?
有两种流水灯

  • 一种是移位流水灯,采用移位方式,同时只能亮一个灯。
    思路:在定时1s完成后加上自增量,该自增量随着秒数累次增加,当达到设计计数时清零。
    代码如下:
#include<reg51.h>
#include<intrins.h>	
int flag=0;
sbit ledPort = P2;

void main()
{
	TMOD=0x10;          //工作于方式1
    EA=1;              // 中断允许
    ET1=1;						 // 中断1打开
	TH1=(65536-50000)/256; 	     // (65536-50000)/256=60.6875
	TL1=(65536-50000)%256;      
	TR1=1;
  while(1){}
}

void timer1(void) interrupt 3
{ 
	unsigned char i;
	TH1=(65536-50000)/256;
	TL1=(65536-50000)%256;
    flag++;
	if (flag==20)	     //达到1s
		{ 
		    i++;
			flag	=0;
			ledPort = ~(1<<i) ;
			i=(i+1)%8;
		}	  			
}

原理图如下所示:


在这里插入图片描述


  • 另外一种是累计流水灯,采用累增方式,同时亮多个灯。
    思路:在定时1s完成后加上自增量,该自增量随着秒数累次增加,当达到设计计数时清零。同时设置多重判断,根据自增量的值判断执行哪一种循环。
  • 其实我这里的写法很蠢,像是没学过 c 的人,可惜实验的时间不够,就采用笨办法了,达到效果就行(狗头)。
  • 高效率的写法应该与C输出九九表类似,采用双重For循环嵌套构成。
    代码如下:
#include<reg51.h>
#include<intrins.h>	
#define ledPort  P2
int flag = 0;
sbit LED1 = P2^0;
sbit LED2 = P2^1;
sbit LED3 = P2^2;
sbit LED4 = P2^3;
sbit LED5 = P2^4;
sbit LED6 = P2^5;
sbit LED7 = P2^6;
sbit LED8 = P2^7;
unsigned char i ;
void main()
{
	
	TMOD=0x10;          //工作于方式1
  EA=1;              // 中断允许
  ET1=1;						 // 中断1打开
	TH1=(65536-50000)/256; 	     // (65536-50000)/256=60.6875
	TL1=(65536-50000)%256;      
	TR1=1;
	i=0;               //用于控制流水灯跳转
  while(1){}
}

void timer1(void) interrupt 3
{ 
  TH1=(65536-50000)/256;
	TL1=(65536-50000)%256;
  flag++;
	if (flag==20)	     //达到1s
		{
			i++;
			flag = 0;
					if(i==1)
					{
						LED1=0;
					}
						if(i==2)
					{
						LED1=0;
						LED2=0;
					}
						if(i==3)
					{
						LED1=0;
						LED2=0;
						LED3=0;
					}				
						if(i==4)
					{
						LED1=0;
						LED2=0;
						LED3=0;
						LED4=0;
					}				
						if(i==5)
					{
						LED1=0;
						LED2=0;
						LED3=0;
						LED4=0;
						LED5=0;
					}
						if(i==6)
					{
						LED1=0;
						LED2=0;
						LED3=0;
						LED4=0;
						LED5=0;
						LED6=0;
					}
						if(i==7)
					{
						LED1=0;
						LED2=0;
						LED3=0;
						LED4=0;
						LED5=0;
						LED6=0;
						LED7=0;
					}
						if(i==8)
					{
						LED1=0;
						LED2=0;
						LED3=0;
						LED4=0;
						LED5=0;
						LED6=0;
						LED7=0;
						LED8=0;
					}
					
					
					
						if(i==9)
					{
						LED1=0;
						LED2=0;
						LED3=0;
						LED4=0;
						LED5=0;
						LED6=0;
						LED7=0;
						LED8=1;
					}
						if(i==10)
					{
						LED1=0;
						LED2=0;
						LED3=0;
						LED4=0;
						LED5=0;
						LED6=0;
						LED7=1;
						LED8=1;
					}
						if(i==11)
					{
						LED1=0;
						LED2=0;
						LED3=0;
						LED4=0;
						LED5=0;
						LED6=1;
						LED7=1;
						LED8=1;
					}
						if(i==12)
					{
						LED1=0;
						LED2=0;
						LED3=0;
						LED4=0;
						LED5=1;
						LED6=1;
						LED7=1;
						LED8=1;
					}					
						if(i==13)
					{
						LED1=0;
						LED2=0;
						LED3=0;
						LED4=1;
						LED5=1;
						LED6=1;
						LED7=1;
						LED8=1;
					}
						if(i==14)
					{
						LED1=0;
						LED2=0;
						LED3=1;
						LED4=1;
						LED5=1;
						LED6=1;
						LED7=1;
						LED8=1;
					}
						if(i==15)
					{
						LED1=0;
						LED2=1;
						LED3=1;
						LED4=1;
						LED5=1;
						LED6=1;
						LED7=1;
						LED8=1;
					}
						if(i==16)
					{
						LED1=1;
						LED2=1;
						LED3=1;
						LED4=1;
						LED5=1;
						LED6=1;
						LED7=1;
						LED8=1;
					}
						if(i==17)
						{
							i=0;
						}


		}	  			
}


  • 实验效果图如下所示:
    在这里插入图片描述
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐