单片机定时器及中断的使用(含原创完整精讲例程)
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
三、中断服务子程序
STC89C52 单片机的中断级别及中断向量表
中断源
默认中断级别
INT0—外部中断 0
最高
T0—TC0 中断
第二
INT1—外部中断 1
第三
T1—TC1 中断
第四
TI/RI—串行口中断
第五
T2—定时器 2 中断
最低
中断号(C 语言用) 0 1 2 3 4 5
入口地址(汇编用) 0003H 000BH 0013H 001BH 0023H 002BH
dula=1;
P0=table[shi]; //送十位数据;
dula=0;
P0=0xff;
wela=1;
P0=0xfd;
//打开第二个数码管;
wela=0;
delay_ms(1);
/**********在第三个数码管上显示个位数字*********/
dula=1;
P0=table[ge];
//送个位数据;
ETx—TCx 中断使能位
ES—串行口中断使能位
EXx—外部中断 x 使能位
注意:使能某一中断时,必须将 EA 置 1。ET2 为 52 系列所有,51 系列没有 TC2。
5. 中断优先级寄存器 IP(B8H,可位寻址,服务清 0)
STC89C52 中断优先级寄存器 IP:
位符号 Reserved Reserved Reserved PS
dula=0;
P0=0xff;
wela=1;
P0=0xfb;
//打开第三个数码管;
wela=0;
delay_ms(1);
}
/************初始化函数**************/
void init()
{ wela=0; dula=0; temp=0;
//初始化数码管;
/****定时器初始化****/
STC89C52 定时器/计数器的使用
一、寄存器
1. 数据寄存器 TLx[1](8AH,8BH,不可位寻址,复位清 0) 8 位寄存器,保存计数值的低 8 位。 THx(8CH,8DH,不可位寻址,复位清 0) 8 位寄存器,保存计数值的高 8 位。 工作原理:计数时,从 TL 开始加 1 计数,计满后想 TH 进位,直至 TH 溢出,置 TF 标
不使用定时器中断,而采用软件查询的方法,则需要软件清零。
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 要变高电平),否则将产生另一次中断。
秒执行一次下面的程序;
{ 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);
C51 的中断函数格式如下: void functionName() interrupt InterruptNum [using groupNum ] {……} 黑体为关键字,斜体为可编辑项,方括号内的为可选项。 函数名(functionName)可以是任何合法的标识符。中断号(InterruptNum)是编译器
注意,中断函数中一定不要写过多的处理语句,否则当前中断尚未处理完,下一次中断 又会到来,这样就会丢失中断。因此,中断服务子程序要高效、简洁。能在主程序中完成 的操作不要在中断函数中完成。
注:定时器的溢出率指该定时器溢出的频率,是两次计数溢出相差时间的的倒数。
四、例程
可将以下代码直接复制到.c 文件中。
4. 中断使能寄存器 IE(A8H,可位寻址,复位清 0)
STC89C52 中断使能寄存器 IE:
位符号 EA Reserved ET2
ES
ET1
EX1
ET0
EX0
位地址 AFH
--
ADH
ACH
ABH
AAH
A9H
A8H
高位在前。所有位均是置 1 开中断,置 0 关中断。
EA—全局中断(总中断)使能位
dula=0;
//段选锁存器锁存;
P0=0xff;
//"消影",避免打开位选时,位选数据受之前段选数据的影响,
造成乱码显示;
wela=1;
//位选锁存器直通;
P0=0xfe;
//送位选数据;0xfe 表明选中第一个数码管;
wela=0;
//位选锁存器锁存;
delay_ms(1);
/**********在第二个数码管上显示十位数字**********/
PT1
PX1
PT0
PX0
位地址 --
--
--
BCH
BBH
BAH
B9H
B8H
所有位均是置 1 为高优先级,置 0 为低优先级。
PS—串行口中断优先级控制位
PT1—TC1 中断优先级控制位
PX1—外部中断 1 优先级控制位
PT0—TC0 中断优先级控制位
PX0—外部中断 0 优先级控制位
同优先级的中断请求,按默认顺序响应。
二、定时器的使用
由于定时器都是由初值计数直至溢出,因此最重要的就是设置计数器的初值。 假设需要定时器产生一次中断的事件为 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 计数
识别不同中断的唯一标识,一定不能有误。工作组(groupNum)指示这个中断函数使用单 片机内存中 4 组工作寄存器中的哪一组,由于编译器会自动分配,常省略不写。
可以在中断函数中为定时器重装初值,这样,就可以实现间隔一定时间的中断。这种方 法会出现累积误差,减小误差的有效方法是使用方式 2,即初值自动重装的定时器方式。
EA=1; ET0=1;
//开总中断; //使能定时器 T0 中断;
TR0=1;
//启动定时器 T0;
}
/*********中断服务子程序**********/
void timer0() interrupt 1 //定时器 T0 中断服务子程序;
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
}
}
/**************延迟 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--);
//数码管编码表(三个数码管均接到 P0 口),code 型占用程序空
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),即每
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,并申请中断。进入中断服务子程序后,硬件自动清零。如果
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。
#include<reg52.h>
//STC89C52
#define uint unsigned int
#define uchar unsigned char
uchar temp;
//需要显示的数值,用于分解为百位、十位、个位数字的原始数值;
uchar num;
//计时辅助变量;
uchar bai;
}
/*************数码管动态显示函数************/
void display(uchar bai,uchar shi,uchar ge)
{
/***********在第一个数码管上显示百位数字**********/
dula=1;
//段选锁存器直通;
P0=table[bai]; //送段选数据,百位数据;
//百位数字;
uchar shi; //十位数字;
uchar ge; //个位数字;
sbit dula=P2^6;
//段选锁存器的使能位;
sbit wela=P2^7;
//位选锁存器的使能位;
uchar code table[]={ 间,不会占用内存空间; 0x3f,0x06,0x5b,0x4f, 0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c, 0x39,0x5e,0x79,0x71};
志,然后申请中断,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 中装入的初值必须是相同的,以保证计数的准确性。
【说明】 1. 本文里类似的 x 均可取值为 0 或 1。 2. TC 指 Timer/Counter,即定时器/计数器。 3. 机器周期是单片机的基本操作周期,一个机器周期内单片机完成一项基本操作,如取指 等。一个机器周期包含 12 个时钟周期。时钟周期是时钟频率的倒数。 4. T0 对应引脚 P3.4,T1 对应 P3.5。 5. INT0 对应 P3.2 引脚,INT1 对应 P3.3 引脚。
范围取模即为 TL 的初值;对其取整,则为 TH 的初值。
编程时的步骤: 写定时器程序时,需要对定时器及中断寄存器进行初始化,过程如下: 1. 设置 TMOD,以确定 Tx 的工作方式; 2. 计算初值,并将初值写入 TH 和 TL; 3. 允许中断,如果使用中断方式,需要对寄存器 IE 中的位进行赋值; 4. 置位 TRx,启动定时或计数。
//重装计数器;
num++;
//约每 50ms 将 num 自增 1。
}