51单片机定时器中断
51单片机定时器中断控制LED闪烁
1. 软硬件条件
- 单片机型号:STC89C52RC
- 继电器模块:FL-3FF-S-Z
- LED小灯泡:高电平亮
- 开发环境:KEIL4
- 烧录软件:stc-isp
- 433m遥控器与解码器
2. 定时器中断原理
2.1 中断部分概念
中断:CPU 暂停当前执行程序转而执行临时发生的事件的过程。
中断源:引发中断的事件。
中断申请:中断源向CPU 发起处理请求。
中断响应过程:CPU暂停当前处理事件转而处理中断事件的过程。
中断系统:支持中断功能的部件。
中断服务程序:中断过程中CPU所执行的程序。
中断断点:被中断程序所中断的正要执行的指令的地址。
2.2 定时器中断
即,在到达设定时间之后CPU 需要暂停当前程序转而执行中断服务程序。
2.3 时钟周期
也称之为震荡周期,是时钟频率的倒数,在单片机中晶振震荡频率为 11.0592M Hz。
T
时钟周期
=
1
f
晶振频率
T_{时钟周期} = \frac{1}{f_{晶振频率}}
T时钟周期=f晶振频率1
2.4 机器周期
在计算机中为了方便管理,将执行指令的过程分为多个阶段,每一个阶段完成一个基本动作,完成一个基本动作所需要的时间就是机器周期。一个机器周期由若干个时钟周期组成。在单片机中一般是12个或者6个。
T
机器周期
=
12
∗
T
时钟周期
=
1.085
u
s
T_{机器周期} = 12*T_{时钟周期} = 1.085us
T机器周期=12∗T时钟周期=1.085us
3. 定时器编程
51单片机定时器需要用到多个寄存器,分别是TMOD、TCON、THx、TLx。
以定时器0为例:
其中TCON 可以按位寻址,可以直接定义每一位的状态。TMOD 不可按位寻址,需要整个8位同时定义。
3.1 TMOD模式寄存器
M0 | M1 | 模式 |
---|---|---|
0 | 0 | 13位定时器/计数器,兼容8048定时模式,TL1只用低5位参与分频,TH1整个8位全用。 |
0 | 1 | 16位定时器/计数器,TL0、TH0全用 |
1 | 0 | 8位自动重装载定时器,当溢出时将TH0存放的值自动重装入TL0 |
1 | 1 | 定时器0此时作为双8位定时器/计数器。TL0作为一个8位定时器/计数器,通过标准定时器0的控制位控制。TH0仅作为一个8位定时器,由定时器1的控制位控制。 |
一般情况下使用定时器0,的16位定时器模式。
TMOD &= 0xF0; // 保留高位 清空低位
TMOD |= 0x01; // 保留高位 设置低位
不推荐采用直接赋值,容易破坏定时器1的配置。
3.2 TCON 控制寄存器
同样以T0为例:
- TF0:定时器计数器中断溢出标志位,溢出时,硬件至1,向CPU提出中断请求,CPU响应中断时,由硬件置0
- TR0:定时器0运行标志由软件置位与清零。当TR0=0时,禁止计数, 当TR0=1,GATE(TMOD.3) = 0,允许T0计时;当GATE(TMOD.3) = 1,记录~INT0高电平接收个数。
3.3 中断方式寄存器
- EA:CPU的总中断允许控制位,EA=1,CPU开放中断,EA=0,CPU屏蔽所有的中断申请。EA的作用是使中断允许形成两级控制。即各中断源首先受EA控制:其次还受各中断源自己的中断允许控制位控制。
- ET0:T0的溢出中断允许位。ET0=1,允许T0中断;ET0=0禁止T0中断。
- ET1:定时/计数器T1的溢出中断允许位。ET1=1,允许T1中断;ET1=0,禁止T1中断。
4. 代码实现
查询方式,没有直接声明中断服务程序
#include "reg52.h"
sbit greenLed = P2^2;
sbit D0 = P1^1;
sbit sw = P1^5;
void Timer0Init(){
TMOD &= 0xF0;
TCON |= 0x01;
//10ms后溢出
TL0 = 0x00;
TH0 = 0xDC;
ET0 = 1;
EA = 1;
TF0 = 0;
TR0 = 0;
}
void init(){
sw = 0;
D0 = 0;
greenLed = 0;
Timer0Init();
}
void main(){
int cnt = 0;
init();
while(1){
if(D0==1){
greenLed = 0;
sw = !sw;
TR0 = !TR0;
while(D0 == 1);
}
if(TF0 == 1){
TF0 = 0; // 没有中断服务程序 没有跳转,一直在主程序
TL0 = 0x00;
TH0 = 0xDC;
cnt++;
if(cnt == 20){
greenLed = !greenLed;
cnt = 0;
}
}
}
}
中断服务方式需要知道中断服务号 定时器0中断服务号为1。
#include "reg52.h"
sbit greenLed = P2^2;
sbit D0 = P1^1;
sbit sw = P1^5;
int cnt = 0;
void Timer0Init(){
TMOD &= 0xF0;
TCON |= 0x01;
//10ms后溢出
TL0 = 0x00;
TH0 = 0xDC;
ET0 = 1;
EA = 1;
TF0 = 0;
TR0 = 0;
}
void Timer0Handler() interrupt 1{ // 中断服务程序
cnt++;
TL0 = 0x00;
TH0 = 0xDC;
cnt++;
if(cnt == 20){
greenLed = !greenLed;
cnt = 0;
}
}
void init(){
sw = 0;
D0 = 0;
greenLed = 0;
Timer0Init();
}
void main(){
init();
while(1){
if(D0==1){
greenLed = 0;
sw = !sw;
TR0 = !TR0;
while(D0 == 1);
}
}
}