51单片机定时器/计数器

一、课前须知:

1、51单片机有两组定时器/计数器,因为既可以定时,也可以计数,所以称之为定时器/计数器。

2、定时器/计数器和单片机CPU是相互独立的。定时器/计数器的工作过程是自动完成的,不需要CPU的参与。

3、51单片机中的 定时器/计数器 是根据 机器内部的时钟 或者是 外部的脉冲信号 对寄存器中的数据加1。

4、有了 定时器/计数器 之后,可以增加单片机的效率,一些简单的重复加1的工作可以交给 定时器/计数器 处理。并且定时器还可以实现精确定时的作用。让CPU去处理一些其他复杂的事情。

5、(CPU时序相关):

        振荡周期:为单片机提供定时信号的振荡源的周期(晶振周期或外加振荡周期)

        状态周期:2个振荡周期为1个状态周期,用S表示。振荡周期又称S周期或时钟周期。

        机器周期:1个机器周期含6个状态周期,12个振荡周期。

        指令周期:完成1条指令所占用的全部时间,它以机器周期为单位。

        例如:

        外接晶振为12MHz时,51单片机相关周期的具体值为:

        振荡周期=1/12us;状态周期=1/6us;机器周期=1us;指令周期=1~4us;

二、定时器/计数器原理

        定时/计数器实质上是一个加1计数器。它随着计数器的输入脉冲进行自加1,也就是每来一个脉冲,计数器就自动加1,,当加到计数器为全1时,再输入一个脉冲就使计数器回零,且计数器的溢出使相应的中断标志位置1,向CPU发出中断请求(定时/计数器中断允许时)。如果定时/计数器工作于定时模式,则表示定时时间已到;如果工作于计数模式,则表示计数值已满。

可见,由溢出时计数器的值减去计数初值才是加1计数器的计数值。

        定时/计数器的实质是加1计数器(16位),由高8位和低8位两个寄存器THx和TLx组成。TMOD是定时/计数器的工作方式寄存器,确定工作方式和功能;TCON是控制寄存器,控制T0、T1的启动和停止及设置溢出标志。

 51单片机定时/计数器的工作由两个特殊功能寄存器控制。TMOD用于设置其工作方式;TCON用于控制其启动和中断申请。

(1)工作方式寄存器TMOD

        工作方式寄存器TMOD用于设置定时/计数器的工作方式,低四位用于T0,高四位用于T1。其格式如下:

GATE是门控位, GATE=0时,用于控制定时器的启动是否受外部中断源信号的影响。只要用软件使TCON中的TR0或TR1为1,就可以启动定时/计数器工作;GATA=1时,要用软件使TR0或TR1为1,同时外部中断引脚INT0/1也为高电平时,才能启动定时/计数器工作。即此时定时器的启动条件,加上了INT0/1引脚为高电平这一条件。(***这里通常设置为0)

C/T :定时/计数模式选择位。C/T =0为定时模式;C/T =1为计数模式。

M1M0:工作方式设置位。定时/计数器有四种工作方式。

--方式0

方式0为13位计数,由TL0的低5位(高3位未用)和TH0的8位组成。TL0的低5位溢出时向TH0进位,TH0溢出时,置位TCON中的TF0标志,向CPU发出中断请求。(**这里不自动重装载,所以在中断处理函数中需要重新赋值TH0和TL0)

定时器模式时有:N=t/ Tcy

计数初值计算的公式为:X=2^13-N。

定时器的初值还可以采用计数个数直接取补法获得。

计数模式时,计数脉冲是T0引脚上的外部脉冲。

门控位GATE具有特殊的作用。当GATE=0时,经反相后使或门输出为1,此时仅由TR0控制与门的开启,与门输出1时,控制开关接通,计数开始;当GATE=1时,由外中断引\脚信号控制或门的输出,此时控制与门的开启由外中断引脚信号和TR0共同控制。当TR0=1时,外中断引脚信号引脚的

高电平启动计数,外中断引脚信号引脚的低电平停止计数。

这种方式常用来测量外中断引脚上正脉冲的宽度。

--方式1

方式1的计数位数是16位,由TL0作为低8位,TH0作为高8位,组成了16位加1计数器 。(**这里不自动重装载,所以在中断处理函数中需要重新赋值TH0和TL0)

计数个数与计数初值的关系为:X=2^16-N 

--方式2

方式2为自动重装初值的8位计数方式。(**这里自动重装载,所以在中断处理函数中不需要重新赋值TH0和TL0)

计数个数与计数初值的关系为:X=2^8-N

工作方式2特别适合于用作较精确的脉冲信号发生器。

 --方式3

方式3只适用于定时/计数器T0,定时器T1处于方式3时相当于TR1=0,停止计数。

工作方式3将T0分成为两个独立的8位计数器TL0和TH0 。 

(2)控制寄存器TCON

TCON的低4位用于控制外部中断,已在前面介绍。TCON的高4位用于控

制定时/计数器的启动和中断申请。其格式如下:

TF1(TCON.7):T1溢出中断请求标志位。T1计数溢出时由硬件自动置TF1为1。CPU响应中断后TF1由硬件自动清0。T1工作时,CPU可随时查询TF1的状态。所以,TF1可用作查询测试的标志。TF1也可以用软件置1或清0,同硬件置1或清0的效果一样。

TR1(TCON.6):T1运行控制位。TR1置1时,T1开始工作;TR1置0时,T1停止工作。TR1由软件置1或清0。所以,用软件可控制定时/计数器的启动与停止。

TF0(TCON.5):T0溢出中断请求标志位,其功能与TF1类同。

TR0(TCON.4):T0运行控制位,其功能与TR1类同。

三、定时器/计数器的使用

初始化程序应完成如下工作:

对TMOD赋值,以确定T0和T1的工作方式。

计算初值,并将其写入TH0、TL0或TH1、TL1。

中断方式时,则对EA赋值,开放定时器中断。

使TR0或TR1置位,启动定时/计数器定时或计数。

计数器初值的计算:

机器周期也就是CPU完成一个基本操作所需要的时间。

计数值N乘以机器周期Tcy就是定时时间t

当你使用12MHZ的外部晶振的时候,晶振周期(振荡周期)=1/12 ,机器周期(1个机器周期等于12个振荡周期)=(1/12) * 12 =1us。(如果采用方式1即为16位定时/计数器,那么一次记满就最多为65536*1us = 65536us

如果用定时器0,并采用方式一(16位定时/计数器),而我们定时1ms的初值是多少呢,1ms/1us=1000。也就是要计数1000个数,初值=65535-1000+1(因为实际上计数器计数到66636才溢出)=64536=FC18H (,可这样赋值:TH0=0xFC((65536-1000)/256);TL0=0x18((65536-1000)%256) );

示例代码(定时器中断):

#include "reg52.h"
#include "intrins.h"

typedef	unsigned char u8;
typedef unsigned int u32;

sbit LED=P0^0;

void delay(u32 i)//i==1 10us
{
	while(i--);
}
/**
 *Funtion:定时器0中断处理函数(格式固定 interrupt 1(1为中断号))
 *IN	 : void
 *OUT    : void
 *
 */
void Timer0() interrupt 1
{
	static u32 i;

	//由于这里定时器0初始化的是方式1(16位定时\计数器),所以这里需要重新赋值初始值(TH0和TL0)
	TH0 = 0xFC;
	TL0 = 0x18;
	i++;
	if(i == 1000)//1s
	{
		i = 0;
		LED = ~LED;
	}
}

/**
 *Funtion:定时器中断0初始化函数
 *IN	 : void
 *OUT    : void
 *
 */
void Timer0Init(void)
{
	//选择为定时器0模式,工作方式1,仅用TR0打开启动
	TMOD |= 0x01;
	//给定时器赋初值,定时1ms
	TH0 = 0xFC;
	TL0 = 0x18;
	//打开定时器0中断允许
	ET0 = 1;
	//打开总中断
	EA = 1;
	//打开定时器
	TR0 = 1;

}

int main( void )
{
	LED=0;

	Timer0Init();

	while(1);

	return 0;
}

  • 46
    点赞
  • 320
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是基于C51单片机的0-9红绿灯倒计时程序,同时利用定时计数器实现精确秒的功能: ```c #include <reg52.h> sbit red = P1^0; // 红灯 sbit green = P1^1; // 绿灯 unsigned char sec = 0; // 秒数 unsigned int count = 0; // 计数器 void timer0_init() // 定时器0初始化 { TMOD = 0x01; // 定时器0工作在模式1,16位定时器模式 TH0 = 0xFC; // 定时器初值为0xFC67,即65536-50000,每50ms中断一次 TL0 = 0x67; ET0 = 1; // 开启定时器0中断 TR0 = 1; // 启动定时器0 EA = 1; // 开启总中断 } void timer0_isr() interrupt 1 // 定时器0中断服务程序 { TH0 = 0xFC; TL0 = 0x67; count++; // 计数器加1 if (count == 20) // 1秒钟 { count = 0; sec++; // 秒数加1 } } void main() { timer0_init(); // 定时器0初始化 while (1) { if (sec >= 10) // 倒计时结束 { red = 1; // 红灯亮 green = 0; // 绿灯灭 } else if (sec >= 5) // 剩余5秒 { red = 0; // 红灯灭 green = 1; // 绿灯亮 } else // 剩余5秒以内 { red = 1; // 红灯亮 green = 0; // 绿灯灭 } } } ``` 程序中利用定时器0中断每隔50ms计数器加1,当计数器累加到20时,即1秒钟,秒数加1。根据秒数的不同,控制红绿灯的状态,当秒数大于等于10时,倒计时结束,红灯亮,绿灯灭;当秒数大于等于5时,剩余5秒,红灯灭,绿灯亮;当秒数小于5时,剩余5秒以内,红灯亮,绿灯灭。通过这种方式实现了0-9的红绿灯倒计时,并且能够精确计时,保证了倒计时的准确性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值