51单片机共有两个16位可编程的定时器/计数器,即定时器T0和定时器T1。它们既有定时功能又有计数功能,通过设置一些相关的特殊功能寄存器就可以选择启用哪一个功能。定时器系统是单片机内部一个独立硬件部分,与CPU和晶振之间通过内部某些控制线连接并相互作用,CPU一旦启动定时功能,定时器便会在晶振的作用下自动计时,当定时器计数器积满之后就会产生中断,通知CPU接下来做什么。
定时器或计数器实质是加一计数器(16位)(其输入脉冲有两个来源,一是由系统时钟振荡器输出脉冲经过十二分频后送来;另外是T0或T1引脚输入的外部脉冲源,每来一个脉冲计数器加1,当加到计数器全为1时,在输入一个脉冲就可使计数器回零,计数器的溢出是的TCON寄存器中TF0或TF1置1,向CPU发出中断请求,如果定时或计数器工作于定时模式,则表示定时时间到了,如果是计数则表示计数值已满)由高八位和低八位两个寄存器组成。
TMOD:定时器/计数器模式控制寄存器(TIMER/COUNTER MODE CONTROL REGISTER) ,确定工作方式和功能
TCON:控制寄存器,控制T0,T1的启动和停止及设置溢出标志。
定时器/计数器模式控制寄存器TMOD是一个逐位定义的8位寄存器,但只能使用字节寻址,其字节地址为89H。其格式为:其中低四位定义定时器/计数器C/T0,高四位定义定时器/计数器C/T1,各位的说明:
GATE——门控制。
GATE=1时,由外部中断引脚INT0、INT1来启动定时器T0、T1。 当INT0引脚为高电平时TR0置位,启动定时器T0; 当INT1引脚为高电平时TR1置位,启动定时器T1。 GATE=0时,仅由TR0,TR1置位分别启动定时器T0、T1。
C/T——功能选择位
C/T=0时为定时功能,C/T=1时为计数功能。 置位时选择计数功能,清零时选择定时功能。
M0、M1——方式选择功能
由于有2位,因此有4种工作方式:
M1M0 工作方式计数器模式 TMOD(设置定时器模式)
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 单片机定时器0设置为工作方式1为TMOD=0x01
TCON: 定时器/计数器控制寄存器(TIMER/COUNTER CONTROL REGISTER)
TMOD分成2段,TCON控制更加精细,分成四段,在本文中只要用到高四段。 TF0(TF1)——计数溢出标志位,当计数器计数溢出时,该位置1。
TR0(TR1)——定时器运行控制位 当TR0(TR1)=0 停止定时器/计数器工作 当TR0(TR1)=1 启动定时器/计数器工作
IE0(IE1)——外中断请求标志位
IT0(IT1)——外中断请求信号方式控制位 当IT0(IT1)=1 脉冲方式(后沿负跳有效)
当IT0(IT1)=0 电平方式(低电平有效)此位由软件置1或清0。
TF0(TF1)——计数溢出标志位
当计数器产生计数溢出时,此位由硬件置1。当转向中断服务时,再有硬件自动清0。计数溢出的标志位的使用有两种情况:采用中断方式时,作中断请求标志位来使用;采用查询方式时,作查询状态位来使用。注意记忆方法,理解单词原形,就绝对不会把TF和TR搞混。TF的F也就是溢出Over Flow的F。TR的R就是运行Run。默认是0不运行,当然要置1才运行
//在写单片机定时器程序时候,在程序开始出需要对定时器及中断寄存器做初始化设置,通常初始化过程如下:对TMOD赋值,以确定T0和T1的工作方式; 计算初值,并将初值写入TH0,TL0或者TH1,TL1; 中断方式时,则对IE赋值,开放中断 使TR0或TR1置位,启动定时器/计数器定时或者计数。
//实现led灯一秒亮灭闪烁
//实现led灯一秒亮灭闪烁#define uhar unsinged char #define uint unsinged intuchar num;void main(){ TMOD=0x01;//设置定时器0为工作方式1(M1 M0为01) TH0=(65536-45872)/256;//装初值11.0582晶振定时50ms数为45872 TL0=(65536-45872)%256; EA=1;//开总中断 ET0=1;//开定时器0中断 TR0=1;//启动定时器0 while(1);//程序停止在这里等待中断发生}void T0_time() interrupt 1{ TMOD=0x01;//重装初值 TH0=(65536-45872)/256; num++;//num每加一次判断一次是否到20次 if(num==20)//如果到了20次,说明1秒时间到 { num=0;//num清0重新计数 led=~led1; }}
编写单片机定时器程序的步骤:
1.对TMOD赋值,以确定T0和T1的工作方式。
2.计算初值,并将初值写入TH0,TL0或TH1,TL1。
3.中断方式时,对IE赋值,开放中断。
4.使TR0或TR1置位,启动定时器/计数器定时或计数。
1.定时器使用方法
1.时间的计算
要实现定时50ms,(65536-T0)x12/12000000=0.05s得T0=15536即0x3c要实现定时tms,可以利用(65536-t)x12/12000000= txE-3;求出t,即可。
2.对TMOD赋值,以确定T0和T1的工作方式
//例子TMOD=0x01; //0b00000001 用的是定时器0,工作在方式1(16位寄存器)TMOD:定时器/计数器模式控制寄存器GATE=1时,由外部中断引脚INT0、INT1来启动定时器T0、T1。 当INT0引脚为高电平时TR0置位,启动定时器T0; 当INT1引脚为高电平时TR1置位,启动定时器T1。 GATE=0时,仅由TR0,TR1置位分别启动定时器T0、T1。 Ⅱ,C/T——功能选择位 C/T=0时为定时功能,C/T=1时为计数功能。 置位时选择计数功能,清零时选择定时功能。 Ⅲ,M0、M1——方式选择功能 由于有2位,因此有4种工作方式 M1 M0 工作方式 计数器模式 TMOD(设置定时器模式) 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
/**********************************************************************************************定时器1的初始化函数************************************************************************************************/void timer1_init() //这里是定时器1初始化函数{ TMOD |= 0x10; //TMOD里 MO 置1 TMOD &= 0xdf; //TOOD里 M1 清零 定时器选择为 16位定时模式 TH1 = 0xFC; //下面2句是 定时器的初值 也就是你定时器需要定时的时间 TL1 = 0x67; TR1 = 1; //启动定时器 }
3.计算初值,并将初值写入TH0,TL0或TH1,TL1。
TH0=(65536-50000)/256; //装定时器初值高8位TL0=(65536-50000)%256; //装定时器初值低8位 TH0=(65536-T0)/256 ;//装定时器初值高8位TL0=(65536-T0)%256 ;//装定时器初值低8位//其中T0是需要计算的时间//一般编程过程并直接计算T0的值,直接写让单片机自己去计算
4.中断方式时,对IE赋值,开放中断。
EA=1; //开 总中断ET0=1; //开 定时器0中断 EA=1;开 总中断 EA=0;关闭 总中断 ET0=1;开 定时器0中断 ET0=0;关闭 定时器0中断 EA=1;开 总中断 EA=0;关闭 总中断 ET1=1;开 定时器1中断 ET1=0;关闭 定时器1中断 /*********** //TR0=1;//启动定时器0 TR0=1;//关闭定时器0 ************/
5.//定时器初始化
/************************************定时器初始化案例******************************************/void timer0Init(){ TMOD=0x01; //0b00000001 用的是定时器0,工作在方式1(16位寄存器) TH0=(65536-50000)/256; //装定时器初值高8位 TL0=(65536-50000)%256; //装定时器初值低8位 EA=1;//开总中断 ET0=1; //开定时器0中断 //TR0=1;//启动定时器0 TR0=1;//关闭定时器0}
6..一般使用定时器的代码步骤
//实现led灯一秒亮灭闪烁#define uhar unsinged char #define uint unsinged intuchar num;void main(){ TMOD=0x01;//设置定时器0为工作方式1(M1 M0为01) TH0=(65536-45872)/256;//装初值11.0582晶振定时50ms数为45872 TL0=(65536-45872)%256; EA=1;//开总中断 ET0=1;//开定时器0中断 TR0=1;//启动定时器0 while(1);//程序停止在这里等待中断发生}void T0_time() interrupt 1{ TMOD=0x01;//重装初值 TH0=(65536-45872)/256; num++;//num每加一次判断一次是否到20次 if(num==20)//如果到了20次,说明1秒时间到 { num=0;//num清0重新计数 led=~led1; }}
/定时器0中断函数#define uhar unsinged char void T0/T1_time() interrupt 1//使用定时器中断1{ TMOD=0X01;//选择了定时器0 方式1 //可以设置TMOD=0x00;0x01;0x10;0x11;共四组方式 TH0=(65536-T0)/256; //装定时器初值高8位 TL0=(65536-T0)%256; //装定时器初值低8位 //T0是需要计算的时间 uchar count=0; if(count==X) { count=0; //清0重新计数 执行程序代码 } //其中X是需要计算次数,比如让定时器定时个1s; //则需要定时器一个50ms的时间; //如果要达成1s则需要执行20次; //让定时器定时个50ms时间,需要这样去写 //TH0=(65536-50000)/256; //TL0=(65536-50000)%256; //让定时器定时个T0时间,需要这样去写 // //TH0=(65536-T0乘10的3次方)/256; //TL0=(65536-T0乘10的3次方)%256; }void main(){ timer0Init();//初始化 //执行程序代码,完成相应的功能; while(1) { //执行程序代码,完成相应的功能; }}void T0_time() interrupt 1{ TMOD=0x01;//重装初值 TH0=(65536-45872)/256; num++;//num每加一次判断一次是否到20次 if(num==20)//如果到了20次,说明1秒时间到 { num=0;//num清0重新计数 led=~led1; }}
/*************************网上程序******************************/
/*************************网上程序******************************/#include"reg51.h"sbit led=P1^1;#define uchar unsigned char//#define uint unsigned intuchar num;//定义全局变量void t0Iint()//定时器0的初始化函数{ TMOD=0x01;//设置定时器0为工作方式1(M1 M0为01) TH0=(65536-50000)/256;//装初值11.0582晶振定时50ms数为45872 TL0=(65536-50000)%256; EA=1;//开总中断 ET0=1;//开定时器0中断}void main(){ t0Iint(); //TMOD=0x01;//设置定时器0为工作方式1(M1 M0为01) // TH0=(65536-50000)/256;//装初值11.0582晶振定时50ms数为45872 //TL0=(65536-50000)%256; //EA=1;//开总中断 //ET0=1;//开定时器0中断 TR0=1;//启动定时器0 while(1);//程序停止在这里等待中断发生}void T0_time() interrupt 1{ //TMOD=0x01;//重装初值 //TH0=(65536-50000)/256; num++;//num每加一次判断一次是否到20次 if(num==20)//如果到了20次,说明1秒时间到 { num=0;//num清0重新计数 led=~led; }}
模板
/**********该程序经过处理更容易懂和套模板利用********************************************/#include"reg51.h"sbit led=P1^1;//定义一个LED灯为1.1引脚#define uchar unsigned char//#define uint unsigned intuchar num;//定义全局变量void timer0Iint()//定时器0的初始化函数{ TMOD=0x01;//设置定时器0为工作方式1(M1 M0为01) TH0=(65536-50000)/256;//装初值11.0582晶振定时50ms数为45872 TL0=(65536-50000)%256; EA=1;//开总中断 ET0=1;//开定时器0中断}void T0_time() interrupt 1{ num++;//num每加一次判断一次是否到20次 if(num==20)//如果到了20次,说明1秒时间到 { num=0;//num清0重新计数 led=~led; }}void main(){ timer0Iint(); TR0=1;//启动定时器0//该步骤也可在初始化写 while(1) { }//程序停止在这里等待中断发生
|