×
单片机 > 单片机程序设计 > 详情

51单片机入门教程(5)——定时器中断

发布时间:2024-05-20 发布时间:
|

写在开头:中断是包括单片机在内的所有微处理器很重要的功能之一,初学单片机必须这一部分的知识。


一、中断的概念

先看百度百科是怎么定义中断的:


中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序,处理完毕后又返回原被暂停的程序继续运行。

—— 百度百科


那么怎么理解中断?看下面的例子。


关于中断:

小A正在学习。这时,他的朋友小B叫他一块儿吃鸡,小A停止学习,转去玩吃鸡游戏。玩了几局后,关掉游戏,继续学习。


关于中断优先级:

小A正在学习。这时,他的朋友小B叫他一块儿吃鸡,小A停止学习,转去玩吃鸡游戏,(吃鸡过程中,小A女朋友打来电话,于是挂机游戏,去接电话,接完电话,继续游戏。)玩了几局后,关掉游戏,继续学习。


几个重要概念:

中断:小A学习被小B打断的过程就称为中断。

中断源:小B被称为中断源。

中断服务程序:小A执行的玩游戏操作称为中断服务程序

中断优先级:小A女朋友的电话比游戏优先级高


在89c52单片机中,有3类中断源:


1、外部中断:当外部中断引脚信号产生跳变(低电平→高电平)时引起中断。

2、定时器/计数器中断:当计数器计满溢出时引起跳变。

3、串口中断:串行端口完成一帧数据的发送/接受时引起(如蓝牙传输)。


其优先级如下表:


中断源 优先级 中断服务号

INT0 – 外部中断0 最高 0

T0 – 定时器/计数器0中断 第2 1

INT1 – 外部中断1 第3 2

T1 – 定时器/计数器1中断 第4 3

串口中断 第5 4

T2 – 定时器/计数器2中断 最低 5

下面以定时器中断为例,讨论中断的编程方法。


二、定时器中断

2.1 软件延时的不足

根据现有的知识,如果要在程序中等待一端时间,想到的操作应该是通过执行若干次空指令,达到延时的效果。

如下:


//延时xms

void delayms(uint xms){

uint i,j;

for(i = 0; i < xms; ++i)

for(j = 0; j < 110; ++j)

;

}


但是,假设要实现以下功能:


1、8位数码管动态扫描显示。

2、LED灯每隔1s闪烁一次。


电路如下:

考虑程序怎么写……


//代码不完整,仅为举例说明

void main(){

P2 = 0x01; //数码管从最低位开始扫描

while(1){

//功能1:执行数码管动态扫描

//P2控制显示哪一个数码管,P0控制数码管显示什么内容

P2 = P2<<1; //扫描更高一位的数码管

P0 = xxxx; //输出段码

delayms(5); //延时5ms后显示下一位数码管

//功能2:执行LED灯闪烁

led = ~led; //LED灯状态取反

delayms(1000); //延时1000ms

}

}


功能1和功能2单独写都没有问题。

但是如果组合在一起,写在一个while循环中,就会有问题了:

一个while循环中有两个延时函数,因此执行一次while循环,共延时了1005ms。这并不是我们所希望的结果。我们希望led闪烁的延时不影响数码管动态扫描的延时。


2.2 中断寄存器

要使用硬件定时,主要涉及到寄存器的操作。51单片机里的关于中断的寄存器如下:


IE – 中断允许控制寄存器

IP – 中断优先级控制寄存器

TMOD – 定时器工作方式寄存器

TCON – 定时器控制寄存器

SCON – 串口控制寄存器

THx/TLx – 定时器初值寄存器


在定时器中断中,需要设置的有TMOD、THx/TLx、TCON、IE。

下面只介绍使用定时器中断所需要设置的寄存器,其余寄存器可自行查阅资料。


2.2.1 中断允许控制寄存器 IE

该寄存器的主要功能是控制中断的开启与关闭,共7个有效位,包含一个全局中断控制位和6个中断源的控制位。

中断允许控制寄存器 IE各位的定义如下表:


序号 D7 D6 D5 D4 D3 D2 D1 D0

符号 EA – ET2 ES ET1 EX1 ET0 EX0

说明:

EA 全局中断允许位,当此位是1时中断可用。(重要)

ET2 定时器/计数器2中断允许位

ES 串口中断允许位

ET1 定时器/计数器1中断允许位

EX1 外部中断1允许位

ET0 定时器/计数器0中断允许位 (重要)

EX0 外部中断0允许位

要使用定时器中断,需要将IE寄存器中的EA位设置为1,以及需要将ETx(x = 0,1,2)设置为1。


2.2.2 定时器工作方式寄存器 TMOD

该寄存器的主要功能是设置定时器/计数器中断的工作方式。如设置位定时器模式、定时器模式的计数位的位数。以下是详细介绍:

定时器工作方式寄存器 TMOD各位的定义如下表:


序号 D7 D6 D5 D4 D3 D2 D1 D0

符号 GATE

C/T¯¯¯C/bar{T}

C/

T

ˉ

M1 M0 GATE

C/T¯¯¯C/bar{T}

C/

T

ˉ

M1 M0

说明:

GATE 定时器/计数器的开关控制选项。常将该位置0,即定时器/计数器的开关控制仅由TCON寄存器中的TRx(x = 0,1)控制。(见2.2.3的TRx)

C/T 定时器模式和计数器模式选择位,将该位置0则为定时器模式。

M1M0 设置定时器/计数器工作方式,常将该两位设置为0 1,其定义如下表:


M1 M0 工作方式

0 0 模式0,13位计数

0 1 模式1,16位计数,常用此模式

1 0 模式2,8位初值自动重装

1 1 模式3,仅适用于T0,分为两个8位计数器,T1停止计数

2.2.3 定时器控制寄存器 TCON

该寄存器用于控制中断,如控制定时器的启动,停止、判断定时器的溢出和中断情况。

定时器控制寄存器 TCON各位的定义如下表:


序号 D7 D6 D5 D4 D3 D2 D1 D0

符号 TF1 TR1 TF0 TR0 IE1 IT1 IE0 IT0

说明:

TF1 定时器1溢出标志位

TR1 定时器1运行控制位,将该位置1时启动定时器1

TF0 定时器0溢出标志位

TR0 定时器0运行控制位,将该位置1时启动定时器0 (重要)

IE1 外部中断1请求标志

IT1 外部中断1触发方式选择位

IE0 外部中断0请求标志

IT0 外部中断0触发方式选择位


2.2.4 定时器初值寄存器 THx/TLx

以定时器T0为例,其的工作原理是,每当晶振产生一次脉冲,就将该寄存器TL0加一,当TL0加满溢出后,将TL0清空,TH0加一,TH0计满后产生定时中断。即TH0与TL0组成了一个16位的计数器,这个计数器可以从0x0000(0)加到0xffff(65535)。


以12Mhz的晶振、定时10ms为例:

51单片机为12分频单片机,因此执行一条指令的时间是12×(1/12M) s,即计数器每1us加一。


若定时10ms,则共需要加10000次。

因此将TH0、TL0设置从(65536-10000)= 55536开始计数。55536 的16进制为0xD8F0。因此将TH0设置为0xD8,TL0 设置为0xF0。


2.3 定时器中断程序写法

首先要初始化定时器,即将命令写入以上的寄存器。 假设使用定时器T0

首先设置定时器工作模式TMOD:GATE设置为0;C/T位设置为0使其工作在定时器模式下;M1M0设置为01,使用16位计数。

因此第一句代码是


TMOD = 0x01; // 0000 0001


然后设置定时器时长THx/TLx:


TH0 = 0xD8;

TL0 = 0xF0;


设置定时器允许寄存器IE,打开中断总开关和T0中断开关


EA = 1;

ET0 = 1;


最后设置定时器控制寄存器TCON,使定时器开始计数


TR0 = 1;


因此,完整的定时器初始化代码如下


void initT0(){

TMOD = 0x01; // 0000 0001.

TH0 = 0xD8; //65536-10000

TL0 = 0xF0; //55536

EA = 1;

ET0 = 1;

TR0 = 1;

}


当定时器计数触发中断时,单片机会调用中断服务程序。中断服务程序的格式如下:


void 函数名() interrupt 中断号 using 工作组

{

//所要执行内容

}


说明:

中断服务函数要写在主函数后面,且不需要声明 。

中断服务函数无返回值,所以用void

函数名可以随便起

interrupt后的中断号由下表的重点服务号确定

using 工作组可省略不写


中断源 优先级 中断服务号

INT0 – 外部中断0 最高 0

T0 – 定时器/计数器0中断 第2 1

INT1 – 外部中断1 第3 2

T1 – 定时器/计数器1中断 第4 3

串口中断 第5 4

T2 – 定时器/计数器2中断 最低 5

因此T0中断服务程序如下:


void t0Intr() interrupt 0

{

//因为执行到此时,计数器已经清零,所以要重新赋值

TH0 = 0xD8; //65536-10000

TL0 = 0xF0; //55536

//下面写需要执行的操作

}


根据以上内容,可设计一个简单定时器电路如下:

其中:


D1灯由定时器控制,每秒闪一次

D2 - D8由软件延时实现流水灯效果,周期为100ms


代码如下


#include

#include

//num为计数器,每10ms将num加一,当num为100时为1s

unsigned char num;

sbit led = P1^0;

//函数声明

void delay100ms(); //软件延时100ms

void initT0(); //初始化定时器T0


void main()

{

unsigned char k ;

//初始化num值

num = 0;

//初始化定时器

initT0();

//初始化led灯

led = 0;

//初始化流水灯

P0 = 0xfe;

k = 0xfe;

while(1)

{

//每100ms流水灯移位一次

k = _crol_(k, 1);

P0 = k;

delay100ms();

}

}

//t0定时器中断服务程序

//每隔10ms进入一次该程序

void t0Intr() interrupt 1

{

TH0 = 0xD8;

TL0 = 0xF0;

num++; //该变量加至100说明为1s

if(num == 100)

{

num = 0;

led = ~led; //翻转led灯状态

}

}

void delay100ms()

{

unsigned char a,b,c;

for(c=19;c>0;c--)

for(b=20;b>0;b--)

for(a=130;a>0;a--);

}


void initT0()

{

TMOD = 0x01;

TH0 = 0xD8;

TL0 = 0xF0;

EA = 1;

ET0 = 1;

TR0 = 1;

}


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
浅谈AVR中定时器几种工作模式