当前位置:文档之家› 单片机定时器及中断的使用(含原创完整精讲例程)

单片机定时器及中断的使用(含原创完整精讲例程)

STC89C52定时器/计数器的使用 一、寄存器 1. 数据寄存器
TLx[1]8AH8BH不可位寻址复位清0 8位寄存器保存计数值的低8位。
THx8CH8DH不可位寻址复位清0
8位寄存器保存计数值的高8位。
工作原理计数时从TL开始加1计数计满后想TH进位直至TH溢出置TF标
志然后申请中断CPU进行中断处理。

2. 模式选择寄存器TMOD89H不可位寻址复位清0

高4位用于控制定时器1低4位用于控制定时器0
GATE—门控制位
=0TC[2]的启停仅由寄存器TCON中的TRx控制
=1TC的启停由外部中断引脚的电平状态和TCON中的TRx共同控制。
C/T—模式选择位
=0定时器对内部机器周期[3]计数
=1计数器对外部输入计数由Tx[4]引脚输入
注意计数模式下从采样到计数值更新需要2个机器周期共24个时钟周期因此
时钟频率为f MHz时最高计数频率为1/2f MHz。
M1M0—工作方式选择位
=00方式013位TH全用TL低5位
=01方式116位THTL全用
=10方式28 位自动重装载定时器当溢出时将 TH 存放的值自动重装入 TL
=11方式3仅适用于T0。定时器 0 此时作为双 8 位TC。TL0 作为一个 8 位TC
通过标准定时器 0 的控制位控制。TH0 仅作为一个 8 位定时器由定时器 1 的控制位控
制。 T1停止计数。
注意在方式2中计数溢出后CPU会自动将THx中的值装入TLx。因此在定时器
启动前在THx和TLx中装入的初值必须是相同的以保证计数的准确性。

3. 控制寄存器TCON88H可位寻址复位清0
位符号
TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0
位地址
8FH 8EH 8DH 8CH 8BH 8AH 89H 88H
高位在前。后4位用于外部中断。
TFx—Tx溢出标志位
Tx计数溢出时硬件置1并申请中断。进入中断服务子程序后硬件自动清零。如果
不使用定时器中断而采用软件查询的方法则需要软件清零。
TRx—Tx运行控制位
置0时关闭Tx。 当GATE=0时TRx=1启动Tx
当GATE=1时TRx=1且INTx=1时启动Tx。
IEx—外部中断x请求标志
接收到外部中断后置1中断响应后硬件清零。
ITx—中断触发方式选择位
ITx=0引脚INTx[5]上低电平触发中断
ITx=1引脚INTx上下降沿触发中断。
注意采用低电平触发方式时低电平必须持续到该中断被 CPU 响应同时在该中断
服务程序执行完之前外部中断源必须被清除INTx要变高电平否则将产生另一次中断。

4. 中断使能寄存器IEA8H可位寻址复位清0
STC89C52中断使能寄存器IE
位符号
EA Reserved ET2 ES ET1 EX1 ET0 EX0

地址
AFH -- ADH ACH ABH AAH A9H A8H
高位在前。所有位均是置1开中断置0关中断。
EA—全局中断总中断使能位
ETx—TCx中断使能位
ES—串行口中断使能位
EXx—外部中断x使能位
注意使能某一中断时必须将EA置1。ET2为52系列所有51系列没有TC2。

5. 中断优先级寄存器IPB8H可位寻址服务清0
STC89C52中断优先级寄存器IP
位符号
Reserved Reserved Reserved PS PT1 PX1 PT0 PX0
位地址
-- -- -- BCH BBH BAH B9H B8H
所有位均是置1为高优先级置0为低优先级。
PS—串行口中断优先级控制位
PT1—TC1中断优先级控制位
PX1—外部中断1优先级控制位
PT0—TC0中断优先级控制位
PX0—外部中断0优先级控制位
同优先级的中断请求按默认顺序响应。

【说明】
1. 本文里类似的x均可取值为0或1。
2. TC指Timer/Counter即定时器/计数器。
3. 机器周期是单片机的基本操作周期一个机器周期内单片机完成一项基本操作如取指
等。一个机器周期包含12个时钟周期。时钟周期是时钟频率的倒数。
4. T0对应引脚P3.4T1对应P3.5。
5. INT0对应P3.2引脚INT1对应P3.3引脚。
二、定时器的使用 由于定时器都是由初值计数直至溢出因此最重要的就是设置计数器的初值。
假设需要定时器产生一次中断的事件为t计算初值的步骤如下 1. 计算机器周期
Tm = 12×T
T为时钟周期是时钟频率的倒数。
2. 计算需要计数的个数
需要计数的个数为N=t/Tm
3. 装填数据寄存器
方式013位THx=(213 – N)/25TLx=(213 – N)%25
方式116位THx=(216 – N)/28TLx=(216 – N)%28 实际的初值即为2n – Nn为定时器位数只需将其放入TH和TL中即可。对TL计数范围取模即为TL的初值对其取整则为TH的初值。

编程时的步骤
写定时器程序时需要对定时器及中断寄存器进行初始化过程如下
1. 设置TMOD以确定Tx的工作方式
2. 计算初值并将初值写入TH和TL
3. 允许中断如果使用中断方式需要对寄存器IE中的位进行赋值
4. 置位TRx启动定时或计数。
三、中断服务子程序 STC89C52单片机的中断级别及中断向量表
中断源 默认中断级别 中断号C语言用 入口地址汇编用
INT0—外部中断0 最高
0 0003H
T0—TC0中断 第二
1 000BH
INT1—外部中断1 第三
2 0013H
T1—TC1中断 第四
3 001BH
TI/RI—串行口中断 第五
4 0023H
T2—定时器2中断 最低
5 002BH

C51的中断函数格式如下
void functionName() interrupt InterruptNum [using groupNum ]
{……}
黑体为关键字斜体为可编辑项方括号内的为可选

项。
函数名functionName可以是任何合法的标识符。中断号InterruptNum是编译器
识别不同中断的唯一标识一定不能有误。工作组groupNum指示这个中断函数使用单
片机内存中4组工作寄存器中的哪一组由于编译器会自动分配常省略不写。
可以在中断函数中为定时器重装初值这样就可以实现间隔一定时间的中断。这种方
法会出现累积误差减小误差的有效方法是使用方式2即初值自动重装的定时器方式。
注意中断函数中一定不要写过多的处理语句否则当前中断尚未处理完下一次中断
又会到来这样就会丢失中断。因此中断服务子程序要高效、简洁。能在主程序中完成
的操作不要在中断函数中完成。
注定时器的溢出率指该定时器溢出的频率是两次计数溢出相差时间的的倒数。


四、例程 可将以下代码直接复制到.c文件中。
#include //STC89C52
#define uint unsigned int
#define uchar unsigned char
uchar temp; //需要显示的数值用于分解为百位、十位、个位数字的原始数值
uchar num; //计时辅助变量
uchar bai; //百位数字
uchar shi; //十位数字
uchar ge; //个位数字
sbit dula=P2^6; //段选锁存器的使能位
sbit wela=P2^7; //位选锁存器的使能位

uchar code table[]={ //数码管编码表三个数码管均接到P0口code型占用程序空
间不会占用内存空间
0x3f,0x06,0x5b,0x4f,
0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,
0x39,0x5e,0x79,0x71};

void display(uchar,uchar,uchar);
void delay_ms(uint);
void init();

void main()
{
init();//初始化子程序
while(1)
{
if(num==20) //num=20时已过去了20*50ms=1s时间12MHz即每
秒执行一次下面的程序
{
num=0; //num清零重新计时
temp++;
if(temp==120)
{
temp=0; //在000-119轮流显示
}
bai=temp/100;
shi=temp%100/10;
ge=temp%10; //将3位整数分解成3个单独的数字
}
display(bai,shi,ge);
} }
/**************延迟1ms12MHz晶振***************/
void delay_ms(uint xms) //unsigned int为16位整数因此参数xms的值最大为65535
{
uint i,j;
for(i=xms;i>0;i--)
for(j=250;j>0;j--);
}
/*************数码管动态显示函数************/
void display(uchar bai,uchar shi,uchar ge)
{
/***********在第一个数码管上显示百位数字**********/
dula=1; //段选锁存器直通
P0=table[bai]; //送段选数据百位数据
dula=0; //段选锁存器锁存
P0=0xff; //"消影"避免打开位选时位选数据受之前段选数据的影响
造成乱码显示
wela=1; //位

选锁存器直通
P0=0xfe; //送位选数据0xfe表明选中第一个数码管
wela=0; //位选锁存器锁存
delay_ms(1);

/**********在第二个数码管上显示十位数字**********/
dula=1;
P0=table[shi]; //送十位数据
dula=0;
P0=0xff;
wela=1;
P0=0xfd; //打开第二个数码管
wela=0;
delay_ms(1);

/**********在第三个数码管上显示个位数字*********/
dula=1;
P0=table[ge]; //送个位数据
dula=0;
P0=0xff;
wela=1;
P0=0xfb; //打开第三个数码管
wela=0;
delay_ms(1);
}
/************初始化函数**************/
void init() {
wela=0;
dula=0;
temp=0; //初始化数码管

/****定时器初始化****/
TMOD=0x01; //模式选择T0、T1均为定时器T1为方式013位实
际本程序未使用T1T0为方式116位
TH0=(65536-50000)/256;
TL0=(65536-50000)%256; //装填初值计50,000个数的时间是
50,000*12*(1/12M)= 50(ms)。12MHz情况下恰好为50ms。

EA=1; //开总中断
ET0=1; //使能定时器T0中断

TR0=1; //启动定时器T0
}
/*********中断服务子程序**********/
void timer0() interrupt 1 //定时器T0中断服务子程序
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256; //重装计数器
num++; //约每50ms将num自增1。
}

相关主题
文本预览
相关文档 最新文档