定时器/计数器
应用场合:定时或延时控制、对外部事件的检测、计数等。
计数器 就是对外部输入脉冲的计数;
定时器 也是对脉冲进行计数完成的,计数的是MCS-51内部产生的标准脉冲,通过计数脉冲个数实现定时。
T0 P3.4
T1 P3.5
T2 P1.0
每个定时器内部结构实际上就是一个可编程的加法器,由编程来设置它工作在定时状态还是计数状态。
单片机复位,定时器数据清零。
定时器/计数器组成: 两个16位的定时器T0和T1,以及他们的工作方式寄存器TMOD和控制寄存器TCON等组成。
定时器T0和T1各由两个8位特殊功能寄存器TH0、TL0、TH1、TH1构成。
TH0(8位)、TL0(8位) =》16位的定时计数器 T0
TH1(8位)、TL1 (8位)=》16位的定时计数器 T1
TH0和TL0:存放定时器T0的初值或计数结果;TH0存放高8位,TL0存放低8位
TH1和TL1:存放定时器T1的初值或计数结果;TH·存放高8位,TL·存放低8位
TMOD:用于设置定时器的工作模式和工作方式;工作方式4种(0、1、2、3)
TCON:用于启动和停止定时器的计数,并控制定时器的状态。
TMOD
M1 M0——工作方式选择位
M1 M0
0 0 方式0,13位定时器/计数器(TH0用低5位,TL0用8位)
0 1 方式1,16定时器/计数器 (TH0用8位,TL0用8位;每次溢出TH0,TL0都会置零)
1 0 方式2,8位常数自动重新装载
1 1 方式3,仅适用于T0,T0分为两个8位;T1停止计数
TCON
特殊功能寄存器TCON的高4位为定时器的运行控制位和溢出标志位,低4位为外部中断的触发方式控制位和锁存外部中断请求源。
TCON格式如下:
D7 D6 D5 D4 D3 D2 D1 D0
TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0
高四位功能:
(1)TF1、TF0 计数溢出标志位
(2)TR1、TR0 计数支行控制位
TRX=1: 启动定时器/计数器工作
TRX=0: 停止定时器/计数器工作
低四位功能:(外部中断)
IE1:外部中断1请求标志位,当外部中断1被触发时置1。
IT1:外部中断1触发方式选择位。当IT1=0,为低电平触发方式;当IT1=1,为下降沿触发方式。
IE0:外部中断0请求标志位,当外部中断0被触发时置1。
IT0:外部中断0触发方式选择位。 当IT0=0,为低电平触发方式;当IT0=1,为下降沿触发方式。
工作原理:
1、通过设置TMOD、TCON 设置定时计数器的工作方式以及工作模式
2、设置定时计数器T0和T1这两个定时计数器寄存器的一个初值
每个机器周期到来时:T0++;当TL0=0xff,TH0++
当TH0=0xff,并且TL0=0xff,称作溢出中断(255*255=65535)
初值=T0溢出值-计数次数
指令周期=机器周期X2
TH0=(定时计数器的初值)/256;
TL0=(定时计数器的初值)%256;
定时器设置
(1) 设置TMOD TMOD=0X01;
(2) 计算出初值
(3) 开放总中断 EA=1;
(4) 启动定时计数器 TR0(1)=1;
(5) 设置中断程序
void fun(void) interrupt 1 —— 定时计数器0溢出中断服务程序
void timer0(void) interrupt 1 using 1
{
……………
}
timer0 是函数名,可以任意取,但是不要和关键字重复。
interrupt 1 是非常重要的,interrupt 是关键字,表示中断,1 表示 1 号中断即定时器 0 中断。
中断号 0~4,分别表示外部中断 0→定时器 0→外部中断 1→定时器 1→串口中断。
using 1 表示使用第 1 组寄存器,51 单片机中一共有 4 组寄存器,每组寄存器是 R0~R7。
#include <STC89C51RC.H>
typedef unsigned char u8;
typedef unsigned int u16;
u16 timer;
sbit led=P1^0;
void Init_timer0(void)
{
TMOD = 0x01; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
TH0=(65535-50000)/256; //给定初值,这里使用定时器最大值从0开始计数一直到65535溢出
TL0=(65535-50000)%256;
EA=1; //总中断打开
ET0=1; //定时器中断打开
TR0=1; //定时器开关打开
}
void main (void)
{
Init_timer0();
while (1) //主循环
{ //主循环中添加其他需要一直工作的程序
// delay(100);//执行100次
}
}
void timer0_Service(void) interrupt 1
{
TH0=(65535-50000)/256; //重新设置初值
TL0=(65535-50000)%256;
timer++;
if(timer==20)
{
timer=0;
led=~led;
}
}
使用模式1
定时器1
/*-----------------------------------------------
名称:定时器1
论坛:www.doflye.net
编写:shifang
日期:2009.5
修改:无
内容:通过定时让LED灯闪烁
------------------------------------------------*/
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
sbit LED=P1^0; //定义LED端口
/*------------------------------------------------
定时器初始化子程序
------------------------------------------------*/
void Init_Timer1(void)
{
TMOD |= 0x10; //使用模式1,16位定时器,使用"|"符号可以在使用多个定时器时不受影响
TH1=0x00; //给定初值,这里使用定时器最大值从0开始计数一直到65535溢出
TL1=0x00;
EA=1; //总中断打开
ET1=1; //定时器中断打开
TR1=1; //定时器开关打开
}
/*------------------------------------------------
主程序
------------------------------------------------*/
main()
{
Init_Timer1();
while(1);
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void Timer1_isr(void) interrupt 3 using 1
{
TH1=0x00; //重新赋值
TL1=0x00;
LED=~LED; //LED闪烁
}
定时器1
定时器2
/*-----------------------------------------------
名称:定时器2
论坛:www.doflye.net
编写:shifang
日期:2009.5
修改:无
内容:通过定时让LED灯闪烁
------------------------------------------------*/
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
sbit LED=P1^0; //定义LED端口
/*------------------------------------------------
定时器初始化子程序
------------------------------------------------*/
void TIM2Inital(void)
{
RCAP2H = (65536-60000)/256;//晶振12M 60ms 16bit 自动重载
RCAP2L = (65536-60000)%256;
ET2=1; //打开定时器中断
EA=1; //打开总中断
TR2=1; //打开定时器开关
}
/*------------------------------------------------
主程序
------------------------------------------------*/
main()
{
TIM2Inital();
while(1);
}
/*------------------------------------------------
定时器中断子程序
------------------------------------------------*/
void TIM2(void) interrupt 5 using 1//定时器2中断
{
TF2=0;
LED=~LED; //指示灯反相
}
定时器2
中断加数码管9999计数
#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器
#include <absacc.h> //包含绝对地址访问库函数
#define SEG1 XBYTE[0xffec]
#define SEG2 XBYTE[0xffed]
#define SEG3 XBYTE[0xffee]
#define SEG4 XBYTE[0xffef]
typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char u8;
sbit led=P1^0; //定义P10口是led
//共阳
u8 code smg[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90 //0-9
};
/*******************************************************************************
* 函 数 名 : Timer0Init
* 函数功能 : 定时器0初始化
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void Timer0Init()
{
TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
TH0=0XFC; //给定时器赋初值,定时1ms
TL0=0X18;
ET0=1;//打开定时器0中断允许
EA=1;//打开总中断
TR0=1;//打开定时器
}
int count;
/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void main()
{
SEG1=SEG2=SEG3=SEG4=0xff;//全灭
Timer0Init(); //定时器0初始化
while(1)
{
SEG4 = smg[count%10];
SEG3 = smg[count/10%10];
SEG2 = smg[count/100%10];
SEG1 = smg[count/1000%10];
}
}
/*******************************************************************************
* 函 数 名 : void Timer0() interrupt 1
* 函数功能 : 定时器0中断函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/
void Timer0() interrupt 1
{
static u16 i;
TH0=0XFC; //给定时器赋初值,定时1ms
TL0=0X18;
i++;
if(i==2000)
{
i=0;
led=~led;
count++;
}
}
数码管9999计数器
定时加数码管9999计数
#include<reg52.h>//包含访问sfr库函数
#include<intrins.h>//包含访问内联库函数
#include <absacc.h>
typedef unsigned int uint; //对数据类型进行声明定义
typedef unsigned char uchar;
sbit P10=P1^0;
sbit k1=P3^2; //包含绝对地址访问库函数
#define SEG1 XBYTE[0xffec]
#define SEG2 XBYTE[0xffed]
#define SEG3 XBYTE[0xffee]
#define SEG4 XBYTE[0xffef]
//共阳
uchar code smg[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90 };//0-9
/*
精确定时1秒闪烁LED
*/
uint count;
main()
{
RCAP2H=0X10; //赋值52 0X1000,溢出30次等于1秒
RCAP2L=0X00;
TR2=1; //启动定时器
ET2=1; //打开定时器0中断
EA=1; //打开总中断
SEG1=SEG2=SEG3=SEG4=0xff;//全灭
while(1)
{
SEG4 = smg[count%10];
SEG3 = smg[count/10%10];
SEG2 = smg[count/100%10];
SEG1 = smg[count/1000%10];
}
}
//定时器2中断
timer2() interrupt 5 //定时器2中断是5号
{
static uchar t;
TF2=0;
t++;
if(t==30)
{
t=0;
count++;
P10=~P10;
}
}
数码管9999计数
定时器0
#include<reg52.h>//包含访问sfr库函数
sbit P10=P1^0;
sbit k1=P3^2;
u16 i;
main()
{
TMOD=0X01;//定时器0,16位工作方式
TR0=1; //启动定时器
ET0=1; //打开定时器0中断
EA=1; //打开总中断
while(1)
{
}
}
//定时器0中断
timer0() interrupt 1 //定时器0中断是1号
{
TH0=0X00; //写入定时器0初始值0X0005
TL0=0X06;
while(k1);
P10=~P10;//反转LED灯的状态
}
精确定时1秒
#include<reg52.h>//包含访问sfr库函数
#include<intrins.h>//包含访问内联库函数
typedef unsigned int u16; //对数据类型进行声明定义
typedef unsigned char uchar;
sbit P10=P1^0;
sbit k1=P3^2;
/*
精确定时1秒闪烁LED
*/
main()
{
RCAP2H=0X10; //赋值52 0X1000,溢出30次等于1秒
RCAP2L=0X00;
TR2=1; //启动定时器
ET2=1; //打开定时器0中断
EA=1; //打开总中断
while(1)
{
}
}
//定时器2中断
timer2() interrupt 5 //定时器2中断是5号
{
static uchar t;
TF2=0;
t++;
if(t==30)
{
t=0;
P10=~P10;
}
}
定时1秒闪烁
外中断
#include<reg52.h>//包含访问sfr库函数
sbit P10=P1^0;
sbit K1=P3^2;
/*
外中断的用法。也就是外部 IO 的中断 INT0,和 INT1。
对应的引脚是 P32 和 P33。
在我们的电路图中,P32 也就是接在 K1 的引脚。
所以当我们按下 P32 接到地的时候,可以触发一个 INT0 中断.
当然,必须预先初始化才会启动。
*/
main()
{
IT0=1;//外中断跳变产生中断
EX0=1;
EA=1; //打开总中断
while(1);
}
int0() interrupt 0
{
P10=~P10;
}
外中断
作者:儒良设计