51单片机有2个16位定时器/计数器:T0,T1,二者功能用法基本相同

定时器步骤

1、设置定时器工作模式寄存器TMOD

B7 B6 B5 B4 B3 B2 B1 B0
GATE C/T M1 M0 GATE C/T M1 M0

C/T :定时器或计数器功能的选择位。C/T=1为计数器,通过外部引脚T0或T1输入计数脉冲。C/T=0时为定时器,由内部系统时钟提供计时工作脉冲。

M1 、M0:T0、T1工作模式选择位:

2、设置计数寄存器的初值

若设置定时器T0为方式1,16位定时/计数器,则其初值计算:(xx为定时时间),

TH0=(65535-xx)/256; TL0=(65535-xx)%256   (由于xx<65535,所以最大定时时间约为65ms。)

当xx=1000时,定时时间为1000us,即1ms。

此时TH0=(65535-1000)/256;TL0=(65535-1000)%256

3、设置定时器控制寄存器TCON

B7 B6 B5 B4 B3 B2 B1 B0
TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0

TF1、TF0:溢出标志位,定时器T0或T1计数溢出时,由硬件自动将此位置“1”

TR1、TR0:为1启动定时器/计数器工作;为0停止定时器/计数器工作

功能1:利用定时器T0控制led亮灭,led全亮0.5s,然后全灭0.5s......实现循环点亮

思路:程序主要分为3个部分:定时器初始化函数、中断服务子程序、主函数:

定时器初始化函数:进行相关的配置

(1)设置定时器T0工作在方式1,16位定时器

(2)TH0、TL0初值计算:定时10ms。TH0=(65535-10000)/256;  TL0=(65535-10000)%256

(3)打开中断总开关 (EA=1)

(4)打开定时器T0中断开关 (ET0=1);

(5)启动T0 (TR0=1)

中断服务子程序:重装初值,并进行相应处理。由于定时器最大定时时间约为65ms,要想实现0.5s的延时,可以设置一个变量count,定时器每溢出一次,count加1,当count=50时,50*10ms=500ms=0.5s,定时时间到,count清零。

主函数:调用定时器初始化函数,执行相应程序。

代码实现:

#include"reg51.h"
#include"intrins.h"
 
#define u8 unsigned char
#define u16 unsigned int
	
u8 count=0;
 
void SelectHc573(u8 n)
{
	switch(n)
	{
		case 4:
			P2=(P2 & 0x1f) | 0x80;
			break;
		case 5:
			P2=(P2 & 0x1f) | 0xa0;
			break;
		
		case 6:
			P2=(P2 & 0x1f) | 0xc0;
			break;
		
		case 7:
			P2=(P2 & 0x1f) | 0xe0;
			break;		
	}
}
 
 
//**************定时器初始化函数*******************************
void Init_timer0() 
{
	TMOD=0x01;              //定时器0的方式1,16位定时/计数器
	TH0=(65535-10000)/256;  //10000us,即10ms
	TL0=(65535-10000)%256;
	EA=1;                  //打开中断的总开关
	ET0=1;                 //打开定时器T0中断开关
	TR0=1;                 //启动T0
}
//**************T0中断服务子程序*******************************
void ServiceTimer0() interrupt 1
{
	count++;
	TH0=(65535-10000)/256;  //重装初值
	TL0=(65535-10000)%256;
	if(count==50)           //10ms循环50次,即50*10ms=500ms
	{
		P0=~P0;								//翻转P0电平
		count=0;							
	}
}
//*********************主函数**********************************
void main()
{
	Init_timer0();   //设置T0相关参数
	SelectHc573(4);
	P0=0xff;					//设初始led状态为全灭
	while(1);
}
	

功能2:利用定时器T0设置一个时-分-秒的计时器

代码如下:但需要注意下面程序设置的定时时间存在误差,中断处理函数中不应该存放过多语句,而且进入、退出中断服务函数时也会引起误差,具体可以下载到开发板中进行观察:

#include"reg51.h"
#include"intrins.h"
 
#define u8 unsigned char
#define u16 unsigned int
 
u8 code SEGnoNot[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};//依次为0、1、2、3、4、5、6、7、8、9、-、全灭的段码
 
u8 count=0;//计数累加值
u8 hour=0,minu=0,sec=0;//时分秒初始值
 
void SelectHc573(u8 n)
{
	switch(n)
	{
		case 4:
			P2=(P2 & 0x1f) | 0x80;
			break;
		case 5:
			P2=(P2 & 0x1f) | 0xa0;
			break;
		
		case 6:
			P2=(P2 & 0x1f) | 0xc0;
			break;
		
		case 7:
			P2=(P2 & 0x1f) | 0xe0;
			break;		
	}
}
//**********************数码管显示相关函数*******************************************
void Delay2ms()		//数码管显示延时函数(视觉暂留)
{
	unsigned char i, j;
 
	_nop_();
	_nop_();
	i = 22;
	j = 128;
	do
	{
		while (--j);
	} while (--i);
}
 
void seg_disp(u8 pos,u8 val)
{
	SelectHc573(6);
	P0=(0x01<<pos);
  SelectHc573(7);
	P0= SEGnoNot[val];
	Delay2ms();
}
//**************定时器初始化函数*******************************
void Init_timer0() 
{
	TMOD=0x01;              //定时器0的方式1,16位定时/计数器
	TH0=(65535-10000)/256;  //10000us,即10ms
	TL0=(65535-10000)%256;
	EA=1;                  //打开中断的总开关
	ET0=1;                 //打开定时器T0中断开关
	TR0=1;                 //启动T0
}
//**************T0中断服务子程序*******************************
void ServiceTimer0() interrupt 1
{
	
	TH0=(65535-10000)/256;  //重装初值
	TL0=(65535-10000)%256;
	count++;
	if(count==100)           //10ms循环100次,即100*10ms=1000ms=1s
	{		
		count=0;
		sec=sec+1;
		if(sec==60)       //60s到了,秒清零,分加1
		{
			minu=minu+1;
			sec=0;
			if(minu==60)    //60分钟到了,分清零,时加1
			{
				hour=hour+1;
				minu=0;
			}
			if(hour==24) 		//24小时到了,时清零,重新计时
				hour=0;
		}				
	}
}
//*********************主函数**********************************
void main()
{
	Init_timer0();   //设置T0相关参数	
	while(1)
	{		
		seg_disp(0,hour/10);
		seg_disp(1,hour%10);
		seg_disp(2,10);
		seg_disp(3,minu/10);
		seg_disp(4,minu%10);
		seg_disp(5,10);
		seg_disp(6,sec/10);
		seg_disp(7,sec%10);
	}
}