定时器/计数器
应用场合:定时或延时控制、对外部事件的检测、计数等。
计数器 就是对外部输入脉冲的计数;
定时器 也是对脉冲进行计数完成的,计数的是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 { …………… }
#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 论坛: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闪烁 }
定时器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; //指示灯反相 }
#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计数
#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; } }
定时器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; } }
外中断
#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; }