目录
1、定时器定义
2、定时器相关寄存器说明
3、定时器相关实例
4、结果与体会
定时/计数器,是一种能够对内部时钟信号或外部输入信号进行计数,当计数值达到设定要求时,向CPU提出中断处理请求,从而实现定时或者计数功能的外设。定时/计数器的最基本工作原理是进行计数。作为定时器时,计数信号的来源选择周期性的内部时钟脉冲;用作计数器时,计数信号的来源选择非周期性的外部输入信号。 不管是定时器还是计数器,本质上都是计数器。
51单片机有两个定时/计数器T0和T1,为16位加法计数器,由低8位TLx和高8位THx两个寄存器组成,最大计数值为65535个计数脉冲。
这里只需记住定时器的配置,知道怎么使用就可以了。首先有两个定时器,T0和T1,(也有的单片机有T2),定时器有4种工作方式0,1,2,3;其中最常用的是方式1(16位),其次是方式2(8位自动重装,串口通讯中断会用到)。
定时器需要配置:TMOD =0x01;配置成使用定时器0,工作方式为1;同理使用定时器1工作方式1:TMOD =0x10;则同时使用两个定时器且工作方式为1,那么可以:TMOD =0x11;
定时器1配置成工作方式2:TMOD =0x20;
比如:如果在定时器T0工作方式下,选择方式二进行,此时如果晶振为12MHZ,即每个脉冲的周期为1us。因此定时器T0的16位工作模式最大的定时时间为65535us,现在要求计时2s,则可以选择每次定时20ms,共计时100次达到要求;而此时高八位和第八位寄存器的值为:
TH0=(65536-20000)/256;
TL0=(65536-20000)%256;
TMOD寄存器:
对于寄存器TMOD来说,高四位定义定时器T1模式;低四位定义定时器T0模式;四位分别为:GATE、C/T、M1、M0;其中M控制工作方式,如下:
GATE | C/T | M1 | M0 | GATE | C/T | M1 | M0 |
工作方式编号 | M1 | M0 | 工作方式 |
0 | 0 | 0 | 13位定时/计数器 |
1 | 0 | 1 | 16位定时/计数器,最大计数值65536 |
2 | 1 | 0 | 自动重装8位定时计数器,最大计数值255 |
3 | 1 | 1 | T0分为两个独立的8为定时/计数器,T1无计数 |
C/T=0:定时功能;C/T=1:计数功能;
GATE=0:由TR0和TR1来启动定时器;GATE=1:由外部中断引脚INT0和INT1启动定时器;
TCON寄存器:
低4位给外部中断请求源使用,高4位给内部中断请求源定时器T0 T1使用
内部请求源:
IE:中断允许寄存器:
EA:中断总控制位。EA=1,CPU开放所有中断;EA=0,CPU禁止所有中断。
ES:串行口中断控制位。ES=1,允许串行口中断;ES=0,屏蔽串行口中断。
ET1:定时/计数器TI中断控制位。ET1=1,允许T1中断;ET1=0,禁止T1中断。
EX1:外部中断1中断控制位。EX1=1,允许外部中断1中断;EX1=0,禁止外部中断1中断。
ET0:定时/计数器T0中断控制位。ET0=1,允许T0中断;ET0=0,禁止T0中断。
EX0:外部中断0中断控制位。EX0=1,允许外部中断0中断;EX0=0,禁止外部中断0断。
总之,对于定时器部分只要记着EA=1:开启总中断;ET0=1:开启定时器T0中断,TR0=1为启动定时器;
定时器0:
void isr_timer_0(void) interrupt 1 //默认中断优先级 1
{
TH0 = (65536-2000)/256;
TL0 = (65536-2000)%256; //定时器重载
display();
}
定时器1:
void isr_timer_1(void) interrupt 3 //默认中断优先级 3
{
TH0 = (65536-2000)/256;
TL0 = (65536-2000)%256; //定时器重载
display();
}
注意:定时器0优先级为1,定时器1为3,串口中断优先级为4,总共有5个中断源
例1:要求L1交替闪烁,间隔为0.5s;
#include
unsigned char count=0;
void Init_Timer0();
void main(){
Init_Timer0();
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF; //初始化
while(1){
}
}
//定时器初始化函数
void Init_Timer0(){
TMOD=0X01; //定时器T0,工作方式2为16为定时/计数器;
TH0=(65536-5000)/256; //高四位寄存器的值;
TL0=(65536-5000)%256; //低四位寄存器的值;
ET0=1; //能定时/计数器中断;
TR0=1; //启动定时器T0 ;
EA=1; //开启总中断;
}
//定时器T0中断服务函数
void time() interrupt 1
{
TH0=(65536-5000)/256;
TL0=(65536-5000)%256;
count++;
if(count==100){
P00=~P00;
count=0;
}
}
例2:要求数码管从0计数到9来回循环,每次间隔为1s;
#include
unsigned code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
unsigned char count=0,num=0;
void Init_Timer0();
void main(){
Init_Timer0();
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF;
P2=0XC0;P0=0X01;P2=0XFF;P0=0XFF;
while(1){
}
}
void Init_Timer0(){
TMOD=0X01;
TH0=(65536-20000)/256;
TL0=(65536-20000)%256;
ET0=1;
TR0=1;
EA=1;
}
void time() interrupt 1
{
TH0=(65536-20000)/256;
TL0=(65536-20000)%256;
count++;
if(count==50){
P0=tab[num];
count=0;
num++;
}
if(num==10){
num=0;
}
}
例3:实现流水灯,时间间隔为1s
#include
unsigned int count=0,i=0;
void Timer0_Init();
void main(){
Timer0_Init();
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF;
while(1){
}
}
void Timer0_Init(){
TMOD=0X01;
TH0=(65536-10000)/256;
TL0=(65536-10000)%256;
ET0=1;
TR0=1;
EA=1;
}
void Timer0_Service() interrupt 1
{
TH0=(65536-10000)/256;
TL0=(65536-10000)%256;
count++;
if(count==100){
count=0;
P0=~(0X01<
例4:按键S7控制数码管DS1的第一个位置显示依次0到9,时间间隔为1s
#include
unsigned int count=0,i=0;
void Timer1_Init();
unsigned char code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90};
void main(){
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF;
P2=0XC0;P0=0X01;P2=0XFF;P0=0XFF;
Timer1_Init();
while(1){
}
}
void Timer1_Init(){
TMOD=0X10;
TH1=(65536-10000)/256;
TL1=(65536-10000)%256;
TR1=1;
ET1=1;
EA=1;
}
void Timer1_Service() interrupt 3
{
if(P30==0){
TH1=(65536-10000)/256;
TL1=(65536-10000)%256;
count++;
if(count==100){
count=0;
P0=tab[i];
i++;
if(i==10) i=0;
}
}
}
这个实例,是通过按键控制数码管数字显示,由于按键抖动问题,例4代码未经消抖处理,反应比较延缓。
对于定时器来说,只要记得寄存器TMOD、TCON、IE各具体位的配置就ok,上面也给出了具体位的含义,理解加记忆,还有默认中断优先级,定时器T0为1,定时器T1为3。要会写定时器初始化函数、服务函数。