第5章 CHAPTER 5 AT89C51的中断系统与定时系统 本章介绍AT89C51中断系统的基本概念和基础知识,外部中断系统、定时器/计数器的结构与功能,有关特殊功能寄存器的含义与功能,以及外部中断系统、定时器/计数器的初始化编程方法。通过本章的学习,应该达到以下目标。 (1) 理解中断系统的基本概念和基础知识。 (2) 掌握AT89C51外部中断系统的结构、功能、控制与使用方法。 (3) 掌握AT89C51定时器/计数器的结构、功能、控制与使用方法。 5.1中断系统介绍 5.1.1中断的概念 单片机在执行正常程序时,系统中出现了急需处理的异常情况,请求CPU迅速去处理,这就是中断。CPU暂时中止当前正在执行的程序,转而去处理这个异常情况。处理完这个异常情况后,CPU再回到原来被中断的程序继续执行。CPU响应中断与中断处理的过程如图5.1所示。 图5.1CPU响应中断与中断 处理的过程 单片机中具有中断处理功能的部件,称为中断系统。中断之后所执行的处理程序,称为中断服务子程序,原来执行的程序称为主程序,主程序被中断的位置称为断点,中断申请的来源称为中断源。中断源向CPU发出的服务请求,称为中断请求。CPU对中断请求的处理过程,称为中断处理或中断服务。 单片机的中断系统主要用于实时控制。所谓实时控制,就是要求单片机能够及时响应和处理中断源发出的中断服务请求。 对于中断源发出的中断服务请求,如果没有中断系统,而采用软件查询的方式,那么,CPU就要定时查询是否有服务请求,不论是否有服务请求,都必须去查询,这将浪费大量的时间。采用中断工作方式,就可以消除CPU在查询方式中的等待现象,有助于提高CPU的工作效率。 5.1.2AT89C51中断系统的结构 AT89C51有5个中断源,分别是两个外部中断、两个定时器/计数器中断、一个串行通信中断。AT89C51中断系统的结构如图5.2所示。 图5.2AT89C51中断系统的结构 中断源的名称、引脚、功能、编号与入口地址如表5.1所示。 表5.1中断源的名称、引脚、功能、编号与入口地址 名称引脚功能编号入 口 地 址 外部中断0INT0(P3.2)外部中断0请求00x0003 T0中断T0(P3.4)T0溢出中断请求10x000B 外部中断1INT1(P3.3)外部中断1请求20x0013 T1中断T1(P3.5)T1溢出中断请求30x001B 串口中断TX(P3.1)、RX(P3.0)TX为发送中断请求,RX为接收中断请求40x0023 5.1.3中断控制 AT89C51通过特殊功能寄存器对中断系统进行控制,所用的特殊功能寄存器分别是定时器/计数器控制寄存器、串口控制寄存器、中断允许寄存器、中断优先级寄存器等。 1. 定时器/计数器控制寄存器(TCON) TCON的字节地址为0x88,可位寻址,位地址为0x88~0x8F,格式如图5.3所示。 图5.3TCON的格式 TCON中与中断系统有关的各标志位的作用如下。 (1) IT0: 外部中断0中断请求触发方式选择位。当IT0=0时,采用电平触发方式,INT0低电平有效; 当IT0=1时,采用跳沿触发方式,INT0负跳变有效。 如果外部中断0为电平触发方式,那么,外部中断申请触发器的状态随着CPU在每个机器周期采样到的INT0引脚电平的变化而变化。在中断服务子程序返回之前,INT0引脚必须变为高电平,否则,CPU返回主程序后会再次响应中断。电平触发方式适合于外部中断以电平输入且中断服务子程序能够清除外部中断请求的情况。 如果外部中断0为跳沿触发方式,那么,外部中断申请触发器能够锁存INT0引脚的负跳变,即使CPU暂时不能响应中断,中断申请也不会丢失。当外部中断0为跳沿触发方式时,连续两次采样,如果一个机器周期采样到INT0引脚为高电平,下一个机器周期采样为低电平,则把中断请求触发器置1,直到CPU响应此中断时,该标志才清0。此时,输入的负脉冲宽度至少保持一个机器周期,才能保证被CPU采样到。跳沿触发方式适合于以负脉冲形式输入的外部中断请求的情况。 (2) IT1: 外部中断1中断请求触发方式选择位,作用与IT0相同。 (3) IE0: 外部中断0的中断请求标志位。当CPU检测到INT0的中断请求有效时,硬件自动使IE0置1,向CPU申请中断。CPU响应此中断时,硬件自动使IE0清0,撤销该中断请求。 (4) IE1: 外部中断1的中断请求标志位,作用与IE0相同。 (5) TR0: 定时器/计数器T0的运行控制位。 (6) TR1: 定时器/计数器T1的运行控制位。 (7) TF0: T0溢出标志位。 (8) TF1: T1溢出标志位。 2. 串口控制寄存器(SCON) SCON的字节地址为0x98,可位寻址,位地址为0x98~0x9F,格式如图5.4所示。 图5.4SCON的格式 SCON的低2位与中断控制有关,作用如下。 (1) RI: 串口的接收中断请求标志位。串口接收完一帧串行数据后,硬件自动使RI置1,向CPU申请中断。CPU响应中断时,硬件不会自动对RI清0,必须在中断服务子程序中用软件对RI清0。 (2) TI: 串口的发送中断请求标志位。CPU将1B的数据写入发送缓冲器SBUF时,就启动一帧串行数据的发送,每发送完一帧数据后,硬件自动使TI置1,向CPU申请中断。CPU响应中断时,不自动对TI清0,必须在中断服务子程序中用软件对TI清0。 SCON的高6位是串行通信控制位,将在第6章详细介绍。 3. 中断允许寄存器(IE) AT89C51通过中断允许寄存器(IE)对5个中断源进行两级控制。所谓两级控制,是指有一个中断允许总控制位EA,配合各个中断源的中断允许控制位,共同实现对中断请求的控制。IE字节地址为0xA8,可位寻址,位地址为0xA8~0xAF,格式如图5.5所示。 图5.5IE的格式 IE中各位的作用如下。 (1) EX0: 外部中断0中断允许位。当EX0=1时,允许外部中断0中断; 当EX0=0时,禁止外部中断0中断。 (2) EX1: 外部中断1中断允许位,作用与EX0相同。 (3) ET0: 定时器/计数器T0的中断允许位。当ET0=1时,允许T0中断; 当ET0=0时,禁止T0中断。 (4) ET1: 定时器/计数器T1的中断允许位,作用与ET0相同。 (5) ES: 串口中断允许位。当ES=1时,允许串口的接收和发送中断; 当ES=0时,禁止串口中断。 (6) EA: 中断允许总控制位。当EA=0时,CPU关闭所有中断请求; 当EA=1时,CPU开放所有中断源的中断请求,但是,这些中断请求能否被CPU响应,还要由IE中相应中断源的允许控制位决定。 AT89C51复位后,IE清0,CPU关闭所有中断请求。因此,在AT89C51复位后,必须通过程序中的指令来开放所需的中断。要使某一个中断源被允许中断,除了IE相应位置1外,还必须使EA=1。 例5.1初始化IE,允许片内两个定时器/计数器中断,禁止其他中断源的中断请求。 解由图5.5知,IE各位的数值为10001010B,因此,初始化IE的语句为“IE=0x8A;”。 4. 中断优先级寄存器(IP) AT89C51中断系统有两个中断优先级,并可实现两级中断的嵌套。所谓两级中断嵌套,是指AT89C51在执行低优先级中断服务程序时,可被高优先级中断请求所中断,待高优先级中断处理完毕后,再返回低优先级中断服务程序。两级中断嵌套的过程如图5.6所示。 图5.6两级中断嵌套的过程 关于中断优先级的关系,有下面两条基本规则。 (1) 低优先级中断服务程序可以被高优先级中断请求所中断,但是,高优先级中断服务程序不能被低优先级中断请求所中断。 (2) 任何一个中断请求,一旦得到响应,就不会被与它同优先级的中断请求所中断。 AT89C51中断系统有两个不可寻址的“优先级激活触发器”。一个用来指示某高优先级的中断正在执行,所有后来的中断均被阻止。另一个用来指示某低优先级的中断正在执行,所有同级中断都被阻止,但是不阻止高优先级的中断请求。 可以由软件设置每个中断源的中断优先级。中断优先级寄存器(IP)的字节地址为0xB8,可位寻址,位地址为0xB8~0xBF,格式如图5.7所示。 图5.7IP的格式 IP中各位的作用如下。 (1) PX0: 外部中断0中断优先级控制位。当PX0=1时,INT0为高优先级中断; 当PX0=0时,INT0为低优先级中断。 (2) PX1: 外部中断1中断优先级控制位,作用与PX0相同。 (3) PT0: 定时器/计数器T0中断优先级控制位。当PT0=1时,T0为高优先级中断; 当PT0=0时,T0为低优先级中断。 (4) PT1: 定时器/计数器T1中断优先级控制位,作用与PT0相同。 (5) PS: 串口中断优先级控制位。当PS=1时,串口为高优先级中断; 当PS=0时,串口为低优先级中断。 AT89C51复位后,IP清0,所有中断源被设置为低优先级中断。 例5.2初始化IP,使两个外部中断请求为高优先级,其他中断请求均为低优先级。 解由图5.7知,IP各位的值为00000101B,因此,初始化IP的语句为“IP=0x05;”。 在执行主程序过程中,若只有一个中断源向CPU发出中断请求,而这时CPU又允许中断,则这个中断请求可以得到响应。当CPU同时收到几个不同优先级的中断请求时,先处理高优先级的中断,后处理低优先级的中断。当CPU同时收到几个同优先级的中断请求时,CPU将按照中断的自然优先级顺序确定响应一个中断请求。中断的自然优先级由硬件形成,如表5.2所示。 表5.2中断的自然优先级 中断源名称中 断 级 别 外部中断INT0 T0中断 外部中断INT1 T1中断串口中断最高优先级 最低优先级 例5.3假设IP的值被设置为0x06。如果5个中断请求同时发生,试分析CPU响应中断的次序。 解十六进制数0x06写成二进制数是0000 0110B,由图5.7知,定时器T0和外部中断INT1被设置成高优先级中断。 由表5.2知,如果5个中断请求同时发生,那么,CPU响应中断的先后次序为: T0中断→INT1中断→INT0中断→T1中断→串行中断。 5.2AT89C51中断处理过程 5.2.1中断响应的条件 1. CPU查询到中断请求的必要条件 中断响应就是CPU接受并处理中断源提出的中断请求。任何中断源发出的中断请求,只有被CPU查询到,才有可能得到CPU的响应。一个中断请求被CPU查询到的必要条件如下。 (1) 该中断源发出中断请求,即该中断源对应的中断请求标志为1。 (2) 该中断源的中断允许标志位为1。 (3) IE寄存器中的中断总允许位EA=1。 2. CPU丢弃中断请求的情况 一般情况下,当CPU查询到有效的中断请求时,就开始响应中断。需要注意的是,并不是CPU查询到的所有中断请求都能立即得到响应,当遇到下列三种情况之一时,CPU将丢弃中断查询结果,不能对中断进行响应。 (1) CPU正在处理同级或高优先级的中断。 (2) 查询所在的机器周期不是当前正在执行指令的最后一个机器周期。此时,只有在当前指令执行完毕后,才能进行中断响应。 (3) 正在执行的指令是子程序返回指令RET、RETI,或是访问IE、IP的指令。按照AT89C51中断系统的规定,CPU需要再去执行完一条指令,才能响应中断请求。 5.2.2中断响应后CPU的工作过程 对于汇编语言程序而言,从响应一个中断请求到中断返回,CPU的工作过程如下。 (1) 由硬件自动生成一条长调用指令“LCALL addr16”,这里的addr16是程序存储区中相应中断的入口地址。各中断源服务子程序的入口地址是固定的,如表2.3所示。例如,对于定时器/计数器T0的中断响应,长调用指令为“LCALL 000BH”。 (2) 生成LCALL 指令后,紧接着就由CPU执行该指令。首先将PC的内容压入堆栈以保护断点,再将中断入口地址装入PC,使程序转到中断入口地址。由于每个中断源的中断区只有8个单元,一般难以安排一个完整的中断服务子程序,因此,通常在各中断区入口地址处放置一条无条件转移指令,使程序转向存放中断服务子程序的地址。 从中断服务子程序的第一条指令到中断返回指令RETI为止,这个过程称为中断处理或中断服务。中断处理一般包括三部分内容: 保护现场、中断源服务和恢复现场。 现场通常包括累加器A、程序状态字PSW、工作寄存器Rn等。如果在中断服务子程序中要用到这些寄存器,那么,在进入中断源服务之前,应该将它们的内容保护起来。中断源服务结束后,在执行RETI指令之前,应该恢复现场。 (3) 中断返回。在汇编语言程序中,中断服务子程序的最后一条指令必须是中断返回指令RETI。CPU执行完这条指令后,把响应中断时所保护的断点地址从堆栈中弹出并装入PC,CPU就从断点处继续执行原来被中断的程序。 如果使用汇编语言进行单片机应用系统程序设计,程序员需要深刻理解上述过程,并且需要在程序中的中断区入口地址处放置无条件转移指令,保护现场,设计中断服务子程序和恢复现场,难度比较大。如果使用C语言进行单片机应用系统程序设计,那么,上述过程中的大部分操作都由编译系统自动完成,程序员只需专注于中断服务子程序设计即可。 5.2.3中断请求的撤销 1. 外部中断请求的撤销 (1) 跳沿触发方式外部中断请求的撤销。CPU响应跳沿触发方式外部中断请求后,硬件自动把中断请求标志位IE0或IE1清0,而外部中断请求信号当跳沿信号过后也就消失了,因此,跳沿触发方式外部中断请求是自动撤销的。 (2) 电平触发方式外部中断请求的撤销。CPU响应电平触发方式外部中断请求后,硬件自动把中断请求标志位IE0或IE1清0,但是,中断请求信号的低电平可能继续存在,CPU在以后的机器周期进行采样时,又会把已经清0的中断请求标志位IE0或IE1重新置1。为了彻底撤销电平触发方式外部中断请求,除了把标志位IE0或IE1清0之外,还要把中断请求信号引脚INT0或INT1从低电平强制改为高电平。为此,可以在系统中增加电平方式外部中断请求的撤销电路,如图5.8所示。 图5.8电平方式外部中断请求的撤销电路 从图5.8可见,用D触发器锁存外来的中断请求低电平,并通过D触发器的输出端Q接到INT0或INT1,因此,增加的D触发器不影响中断请求。中断响应后,为了撤销中断请求,可以利用D触发器的直接置1端SD来实现。例如,把SD端接AT89C51的P1.0,只要在P1.0输出一个负脉冲,就可以使D触发器置1,撤销低电平的中断请求。 所需的负脉冲可在中断服务子程序中通过指令得到。因此,电平触发方式的外部中断请求信号的完全撤销,需要软件、硬件结合来实现。 2. 定时器/计数器中断请求的撤销 CPU响应定时器/计数器中断请求后,硬件自动把中断请求标志位TF0或TF1清0,因此,定时器/计数器中断请求是自动撤销的。 3. 串口中断请求的撤销 CPU响应串口中断请求后,硬件不对标志位TI和RI清0,因为在响应串口中断后,CPU无法知道是发送中断还是接收中断,还需要测试这两个中断标志位的状态,以判定是发送操作还是接收操作,然后才能清除。因此,串口中断请求只能用软件撤销。用软件撤销的方法是,在中断服务函数中把串口中断标志位TI或RI清0。 5.2.4采用中断时程序设计的任务 单片机采用中断时,程序设计的基本任务如下。 (1) 设置中断允许寄存器IE。 (2) 设置中断优先级寄存器IP。 (3) 对于外部中断,设置中断的触发方式。 (4) 在主函数外,编写中断服务函数,处理中断请求。 前3条任务一般放在主函数的初始化程序段中。 例5.4假设允许外部中断0中断,采用跳沿触发方式,并设定它为高优先级中断,其他中断源为低优先级中断。试编写主函数的初始化程序段。 解在主函数的初始化部分,编写如下程序段。 IE=0x81;//IE=10000001B,中断总允许开,允许INT0中断 IT0=1;//INT0为跳沿触发方式 PX0=1;//INT0为高优先级中断 单片机采用中断时,程序设计的关键是编写中断服务函数。中断服务函数的格式为: void 函数名(void) interrupt n using m { 中断服务函数内容 } interrupt n指出该中断服务函数所对应的中断源的编号,其中,n的取值如表5.1所示。编译器将在对应的中断入口地址处添加跳转指令,跳到本中断服务函数。using m用于指定本函数所使用的当前工作寄存器,m的取值为0~3。该修饰符可以省略,由编译器自动分配。 编写中断服务函数时,应该注意以下几点。 (1) 在中断服务函数的函数名后面,必须加上“interrupt n”,用来指出该中断服务函数所对应的中断源的编号,n的取值为0~4。 (2) 中断服务函数不能带参数,否则会导致编译错误。 (3) 中断服务函数没有返回值,函数类型必须为void。 (4) 中断服务函数因中断源触发而由CPU自动调用,不能在程序中直接调用,因此,不必提前声明。 (5) 中断服务函数要简短,避免因执行时间过长而影响CPU对其他中断的响应。 (6) CPU在执行一个低级中断的中断服务函数时,如果有高级中断申请,CPU应该暂停执行该中断服务函数,而去执行高级中断的中断服务函数,待高级中断的中断服务函数执行完毕后,再回到中断点,接着执行低级中断的中断服务函数。换句话说,中断服务函数可以嵌套执行。但是,这种嵌套执行是由CPU决定的,在编写一个中断服务函数时,不能嵌套调用另一个中断服务函数。 5.3外部中断 5.3.1外部中断程序设计 单片机的外部中断主要用于解决单片机应用系统正常运行过程中出现的紧急情况,其输入信号来自于单片机的外部。AT89C51中断系统有两个外部中断INT0和INT1,每个中断有两个中断优先级,可以实现两级中断的嵌套。如果一个单片机应用系统只需要一个外部中断,那么,外部中断输入信号可以连接到INT0或INT1中的一个,并且不需要设置中断优先级。如果一个单片机应用系统需要两个外部中断,那么,两个外部中断输入信号可以分别连接到INT0和INT1,并且可以根据实际控制需要设置中断优先级。 一般来说,外部中断编程需要进行下面的设计。 (1) 在主函数的初始化程序段中,通过TCON设置外部中断触发方式IT0、IT1,通过IP设置外部中断的优先级,通过IE开外部中断EX0、EX1,开总中断允许EA。 (2) 在主函数外,编写中断服务函数,实现外部中断的功能。 5.3.2外部中断应用举例 在Proteus仿真平台进行仿真实验时,可以用闸刀开关或按钮开关来模拟外部中断。 图5.9指拨开关 闸刀开关具有保持功能。将开关拨动到ON时,内部的开关接通,形成通路; 若要断开通路,则需要再次拨动开关。比较典型的闸刀开关是指拨开关,如图5.9所示。指拨开关可以是一个独立的开关,也可以把几个独立的开关封装起来。一个独立的指拨开关只有两个引脚,在进行电路设计时,把这两个引脚接入电路,即可控制电路的通断。 常用的按钮开关是轻触开关,具有自动回弹功能。按下按钮时,开关接通; 松开按钮时,开关断开。按钮开关有4个引脚,引脚1与引脚4连通,引脚2与引脚3连通,如图5.10所示。在进行电路设计时,把对角的两个引脚接入电路,即可控制电路的通断。 图5.10按钮开关 例5.5单片机引脚P1.0连接一个LED,引脚INT0(P3.2)连接按键S1。试编写程序,实现如下功能: 每次按键S1按下后,改变LED的亮灭状态。 分析: 从应用系统的功能需求可知,本应用系统用到外部中断INT0。由于只有一个中断源,因此不需要设置中断优先级。 解(1) 硬件系统设计。外部中断控制LED亮灭的电路原理图如图5.11所示。 图5.11外部中断控制LED亮灭的电路原理图 (2) 软件系统设计。控制程序如下。 #include sbit LED=P1^0; sbit KEY=P3^2; /*外部中断服务函数*/ void int0_ISR(void) interrupt 0 { LED=~LED; } main(void) { IT0=1; //跳沿触发方式 EX0=1;//开INT0中断允许 EA=1; //开中断允许总开关 LED=0;//LED点亮 while(1); } 说明: (1) 在主函数的初始化程序段中,设置外部中断0为跳沿触发方式,开INT0中断允许,开中断允许总开关。这里,通过位操作进行初始化设置。 (2) 程序执行时,在正常情况下,LED点亮,执行语句“while(1);”,等待外部中断。当按键S1按下时,有外部中断请求,程序自动跳到外部中断0的外部中断服务函数“void int0_ISR(void)”,改变LED的亮灭状态。然后,程序又回到原来被中断的地方,继续执行语句“while(1);”,等待下一次外部中断。 例5.6单片机引脚P1.0、P1.1、P1.2分别连接一个LED,名称分别为D0、D1、D2,引脚INT0(P3.2)上连接按键S1,引脚INT1(P3.3)上连接按键S2。试编写程序,实现如下功能: 系统正常运行时,D0点亮; 按键S1按下时,D0熄灭,D1点亮; 按键S2按下时,D0熄灭,D2点亮; D1点亮时,按键S2按下时,D1熄灭,D2点亮; D2点亮时,按键S1按下时,LED状态不变。 分析: 从应用系统的功能需求可知,本应用系统用到两个外部中断INT0和INT1,而且INT0是低级中断,INT1是高级中断。 解(1) 硬件系统设计。两个外部中断源的电路原理图如图5.12所示。 图5.12两个外部中断源的电路原理图 (2) 软件系统设计。控制程序如下。 #include #define uint unsigned int//重新定义关键字,简化程序 sbit LED0=P1^0; sbit LED1=P1^1; sbit LED2=P1^2; sbit KEY1=P3^2; sbit KEY2=P3^3; /*用二重循环设计的延时函数*/ void delay(uint n) { uint a,b; for(a=0;a sbit LED=P1^0; main(void ) { unsigned char counter;//用于统计定时器计满溢出的次数 TMOD=0x01;//T0工作方式1,定时模式,由TR0控制启停 TH0=(65536-50000)/256;//装填TH0的初值 TL0=(65536-50000)%256;//装填TL0的初值 TF0=0;//初始化定时器溢出标志 LED=1;//关闭LED counter=0;//计时次数从0开始 TR0=1;//启动定时器T0 while(1) { while(TF0==1)//查询方式: 定时器溢出 { counter++;//计时次数加1 if(counter==20)//计时次数达到20,计时达到1s { LED=~LED;//LED取反,使LED闪烁 counter=0;//计时次数重新从0开始 } TH0=(65536-50000)/256;//重新装填TH0的初值 TL0=(65536-50000)%256;//重新装填TL0的初值 TF0=0;//采用查询方式时,需要用程序把TF0清0 } } } (3) 采用中断方式,控制程序如下。 #include sbit LED=P1^0; unsigned char counter;//用于统计定时器中断次数 /*定时器T0中断服务函数*/ void T0_ISR(void) interrupt 1 { counter++;//中断次数加1 TH0=(65536-50000)/256;//重新装填TH0的初值 TL0=(65536-50000)%256;//重新装填TL0的初值 } main(void) { TMOD=0x01;//T0工作方式1,定时模式,由TR0控制启停 TH0=(65536-50000)/256;//装填TH0的初值 TL0=(65536-50000)%256;//装填TL0的初值 IE=0x82;//允许T0中断 LED=1;//关闭LED counter=0;//中断次数从0开始 TR0=1;//启动定时器T0 while(1) { if(counter==20)//中断次数达到20,计时达到1s { LED=~LED;//LED取反,使LED闪烁 counter=0;//中断次数重新从0开始 } } } 说明: (1) 使用定时器/计数器时,如果采用查询方式,那么,在程序执行过程中,CPU需要不断查询定时器T0溢出标志位TF0的值,即在采用查询方式的控制程序中,不断执行循环结构语句“while(TF0==1)”,这将浪费CPU的时间,降低CPU的效率。如果采用中断方式,那么,在程序执行过程中,CPU不需要查询TF0的值,当TF0=1时,系统会自动跳到定时器T0中断服务函数,执行完中断服务函数后,再回到中断点继续执行被中断的程序,这样就不会降低CPU的效率。 (2) 由于定时器/计数器在工作方式0和工作方式1时没有自动装载初值功能,因此,定时器/计数器每次溢出后,必须重新装载计数初值。 例5.8设计流水灯的电路原理图,编写程序,实现如下功能: 使用定时器T0中断实现流水灯,流水频率为每0.5s更替一次。 解(1) 硬件系统设计。流水灯的电路原理图如图5.21所示,P0连接8个LED。 图5.21流水灯的电路原理图 (2) 软件系统设计。单片机外接12MHz的晶振,定时器/计数器T0采用中断方式,控制程序如下。 #include unsigned char cnt=0;//用于统计定时器中断次数 unsigned char led =0xfe;//初始化流水灯 int main(void) { TMOD=0x01;//T0工作方式1,定时模式,由TR0控制启停 TH0=(65536-50000)/256;//装填TH0的初值 TL0=(65536-50000)%256;//装填TL0的初值 EA=1;//总中断允许开 ET0=1;//T0中断允许开 TR0=1;//启动定时器T0 while(1);//等待中断 } void T0_ISR(void) interrupt 1 { cnt++; if(cnt==10)//0.5s时间到 { cnt=0;//清除中断次数统计 led=(led<<1)|1;//更新流水灯数据 if(led==0xff) { led=0xfe; } P0=led;//显示流水灯 } TH0=(65536-50000)/256;//重新装填TH0的初值 TL0=(65536-50000)%256;//重新装填TL0的初值 } 说明: 本例把更新流水灯数据等操作放在定时器T0的中断服务函数中,这样处理比较直观,程序容易理解,但是,中断服务函数就需要比较长的时间。如果在执行中断服务函数期间又出现新的低优先级或同优先级的中断,那么,这个新的中断就不能得到及时响应。而在例5.7中,定时器T0的中断服务函数很简短,因此不会出现这个问题。读者可以参照例5.7,对本例的程序进行优化。 5.5.3定时器/计数器工作方式2的应用 定时器/计数器工作在方式0和方式1时,计数溢出后计数器被清0,当进行循环定时或循环计数时,需要反复装填计数初值,这使得程序设计变得烦琐,并且影响计时精度。而定时器/计数器的工作方式2能够自动装填计数初值。 在工作方式2下,把16位计数器被分为两部分,以TL0作为计数器,以TH0作为存储器,用于存储计数初值。初始化时,把计数初值分别装填到TL0和TH0中。当计数溢出时,不需要用程序重新装填计数初值,而是由存储器TH0自动给计数器TL0装填计数初值。 例5.9设计产品包装生产线计数系统,每包有5件产品。每个产品经过计数装置时,由机械杆碰合按键S1一次。当计满第一包时,指示灯D0点亮; 当计满第二包时,指示灯D1点亮; ……; 当计满第八包时,指示灯D0~D7全亮。重复以上过程。 分析: 把单片机的T1(P3.5)引脚连接一个按键S1,当每个产品经过计数装置时,由机械杆碰合按键S1一次,T1引脚由高电平变为低电平,产生一个负跳变。因此,可以T1作为计数器,对负跳变进行计数。由于一包产品只有5个,数量较少,用8位二进制数完全可以满足计数需要,因此,使T1工作在方式2。 解(1) 硬件系统设计。产品包装生产线计数系统如图5.22所示,单片机的T1(P3.5)引脚连接一个按键S1,P0连接8个LED,代表指示灯D0~D7。 图5.22产品包装生产线计数系统 (2) 软件系统设计。定时器/计数器T1采用查询方式,控制程序如下。 #include unsigned char counter;//统计包的数量 main(void) { TMOD=0x60;//T1工作方式2,计数模式,由TR1控制启停 TH1=256-5;//T1高8位赋初值 TL1=256-5;//T1低8位赋初值 counter=0; TR1=1;//启动T1 while(1) { while(TF1==1)//查询方式: 计满一包 { TF1=0;//无中断服务程序,需要用程序把TF1清0 counter++;//包的计数加1 switch(counter)//检查包的数量 { case 1: P0=0xfe; break;//1包满,第1个灯亮 case 2: P0=0xfd; break;//2包满,第2个灯亮 case 3: P0=0xfb; break;//3包满,第3个灯亮 case 4: P0=0xf7; break;//4包满,第4个灯亮 case 5: P0=0xef; break;//5包满,第5个灯亮 case 6: P0=0xdf; break;//6包满,第6个灯亮 case 7: P0=0xbf; break;//7包满,第7个灯亮 case 8: P0=0x00; counter=0; break;//8包满,8个灯全亮,包的数量清0 } } } } 5.5.4外部中断与定时器/计数器综合应用 例5.10设计流水灯的电路原理图,编写控制程序,实现如下功能: 通过按键改变流水灯的流动方向,使用定时器控制流水灯的切换时间。 分析: 本例综合利用外部中断与定时器/计数器来控制流水灯,以按键作为外部中断信号的输入设备,以定时器/计数器的定时方式进行计时。 解(1) 硬件系统设计。流水灯的电路原理图,如图5.23所示,单片机的INT0(P3.2)引脚连接一个按键S1,P0连接8个LED。 图5.23流水灯的电路原理图 (2) 软件系统设计。单片机外接12MHz的晶振,定时器/计数器T0采用中断方式,控制程序如下。 #include unsigned char cnt=0;//用于统计定时器中断次数 bit flag=0;//外部中断标识 unsigned char led=0xff;//初始化流水灯 int main(void) { IT0=1;//外部中断INT0跳沿触发方式 TMOD=0x01;//T0工作方式1,定时模式,由TR0控制启停 TH0=(65536-50000)/256;//装填TH0的初值 TL0=(65536-50000)%256;//装填TL0的初值 IE=0x83;//开中断允许 TR0=1;//启动T0工作 while(1) { if(flag==0) { if(cnt==10)//0.5s时间到 { cnt=0;//定时器中断次数清0 led=(led<<1)|1;//更新流水灯数据 if(led==0xff) { led=0xfe; } P1=led;//显示流水灯 } } else { if(cnt==10)//0.5s时间到 { cnt=0;//定时器中断次数清0 led=(led>>1)|0x80;//更新流水灯数据 if(led==0xff) { led=0x7f; } P1=led;//显示流水灯 } } } } /* INT0中断服务函数*/ void int0_ISR(void) interrupt 0 { flag=~flag; } /*定时器T0中断服务函数*/ void T0_ISR(void) interrupt 1 { cnt++; TH0=(65536-50000)/256; TL0=(65536-50000)%256; } 在很多实际应用中,需要各种不同频率、不同波形的数字信号,例如,方波、锯齿波、三角波、脉冲宽度调制(Pulse Width Modulation,PWM)波等。特别是方波,应用最为广泛。例如,在单片机串行通信时,就需要生成一定频率的方波,来控制波特率。可以利用单片机的定时器/计数器生成不同频率的方波。 例5.11设计生成不同频率方波的仿真电路,编写控制程序,实现如下功能: 使用外部中断方式控制按键,通过按键控制单片机的某个引脚分别输出频率为100Hz、1kHz的方波。 分析: 所谓方波,就是在一个周期内,高电平和低电平各占一半的波形。因此,只需在单片机的某个引脚输出半个周期的高电平,再输出半个周期的低电平,如此循环往复,就可以得到所需的方波。 解(1) 硬件系统设计。产生不同频率方波的电路原理图如图5.24所示,单片机INT1(P3.3)引脚连接一个按键S1,P2.0连接一个示波器。 图5.24产生不同频率方波的电路原理图 (2) 软件系统设计。单片机外接12MHz的晶振,定时器/计数器T0采用中断方式,控制程序如下。 #include sbit P2_0=P2^0; unsigned int cnt=0;//用于统计定时器中断次数 bit flag=0;//外部中断标识 int main(void) { IT1=1;//外部中断INT1,跳沿触发方式 TMOD=0x02;//T0工作方式2,定时模式,由TR0控制启停 TH0=256-250;//装填TH0的初值 TL0=256-250;//装填TL0的初值 IE=0x86;//开中断允许 TR0=1;//启动T0工作 while(1) { if(flag==0)//产生100Hz的方波 { if(cnt==20)//0.005s时间到 { cnt=0;//定时器中断次数清0 P2_0=~P2_0; } } else//产生1kHz的方波 { if(cnt==2)//0.0005s时间到 { cnt=0;//定时器中断次数清0 P2_0=~P2_0; } } } } /* INT1中断服务函数*/ void int1_ISR(void) interrupt 2 { flag=~flag; } /*定时器T0中断服务函数*/ void T0_ISR(void) interrupt 1//定时器T0中断服务函数 { cnt++; } 说明: (1) 一般来说,在使用方波作为控制信号时,要求信号的频率参数尽可能精确,即要求信号的高电平部分和低电平部分的时间尽可能精确。因此,可以使用定时器/计数器的工作方式2,自动装填初值,提高计时的精确度。本例就是使用定时器/计数器的工作方式2。 (2) 对于频率比较低的方波,半个周期的时间比较长,而定时器/计数器的工作方式2一次计时时间很短,需要定时器中断很多次,而程序需要不断查询定时器中断次数变量,这也会浪费很多时间,影响计时精度。此时,可以考虑使用定时器/计数器的工作方式1,由于一次中断的时间比较长,定时器只需中断较少的次数就可以达到半个周期的时间。 习题 一、 选择题 1. 各中断源发出的中断请求信号,都会标记在AT89C51的中。 A. IE寄存器B. TMOD寄存器 C. IP寄存器D. TCON与SCON寄存器 2. 在AT89C51的中断源中,需要外加电路实现中断撤销的是。 A. 电平触发方式的外部中断B. 串行中断 C. 跳沿触发方式的外部中断D. 定时中断 3. 当外部中断0发出中断请求后,中断响应的必要条件是。 A. ET0=1B. EX0=1C. IE=0x81D. IE=0x61 4. AT89C51的中断系统有两个中断优先级,各中断源的优先级设定是利用特殊功能寄存器。 A. IEB. IPC. TCOND. SCON 5. 下列说法中,错误的是。 A. 同一级别的中断请求按时间的先后顺序响应 B. 同一时间同一级别的多中断请求将形成阻塞,系统无法响应 C. 低优先级中断请求不能中断高优先级中断服务程序 D. 同级中断不能嵌套 6. 单片机默认的最高等级中断源是。 A. 定时器T0B. 定时器T1C. 外部中断INT0D. 外部中断INT1 7. AT89C51在同一优先级的中断源同时申请中断时,CPU首先响应。 A. INT0中断B. INT1中断C. T0中断D. T1中断 8. 如果将中断优先级寄在器IP设置为0x0A,则优先级最高的是。 A. INT1B. INT0C. T1D. T0 9. 在AT89C51中,与外部中断无关的特殊功能寄存器是。 A. TCONB. TMODC. IED. IP 10. 当外部中断请求为跳沿触发方式时,要求中断请求信号的高电平状态和低电平状态都应至少维持个机器周期。 A. 1B. 2C. 4D. 12 11. AT89C51的外部中断INT1的中断请求标志是。 A. ETIB. TEIC. IT1D. IE1 12. 在AT89C51中,与定时器/计数器中断无关的特殊功能寄存器是。 A. TCONB. TMODC. SCOND. IP 13. 溢出后不用重装计数初值,定时器/计数器的工作方式为。 A. 方式0B. 方式1C. 方式2D. 方式3 14. 若TMOD中的M1M0为11,则设置定时器/计数器工作于。 A. 方式0B. 方式1C. 方式2D. 方式3 15. 使AT89C51的定时器T0 停止计数的语句是。 A. TR0=1;B. TR0=0;C. TR1=1;D. TR1=0; 16. 若要求最大定时时间为216个机器周期,则应使定时器/计数器工作于。 A. 方式0B. 方式1C. 方式2D. 方式3 17. 晶振频率为12MHz的单片机,在定时工作模式下,定时器可能实现的最大定时时间为。 A. 4096μsB. 8192μsC. 65536μsD. 32768μs 18. 设定时器/计数器T0的初始化程序段如下: TMOD=0x06; TH0=0xFF; TL0=0xFF; EA=1; ET0=1; 则执行该程序段后,把定时器/计数器T0的工作状态设置为。 A. 工作方式0,定时应用,定时时间为2μs,中断禁止 B. 工作方式1,计数应用,计数值为255,中断允许 C. 工作方式2,定时应用,定时时间为510μs,中断禁止 D. 工作方式2,计数应用,计数值为1,中断允许 19. 单片机定时器/计数器根据需要有4种工作方式,其中工作方式1是。 A. 16位的定时器/计数器B. 13位的定时器/计数器 C. 8位可自动重载的定时器/计数器D. 两个独立的8位定时器/计数器 20. 应用单片机定时器/计数器时,控制T0的启动和停止的关键字是。 A. TMODB. TR0C. ET0D. TF0 21. AT89C51外接6MHz的晶振,采用16位定时器计时50ms,则设置定时器的计数初值为。 A. 0B. 65536C. 50000D. 40536 22. 若AT89C51的振荡频率为6MHz,设定时器工作在方式0需要定时1ms,则定时器初值应为。 A. 500B. 1000C. 7692D. 7192 23. 定时器/计数器T1工作在计数模式时,外加的计数脉冲信号应连接到引脚。 A. P3.2B. P3.3C. P3.4D. P3.5 24. AT89C51的定时器/计数器T0用于定时,采用工作方式1,则初始化编程为。 A. TMOD=0x01B. TMOD=0x50C. TMOD=0x10D. TCON=0x02 25. AT89C51内部有个16位的定时器/计数器,其中,定时器/计数器T1有种工作方式。 A. 4,5B. 2,4C. 5,2D. 2,3 26. AT89C51的定时器/计数器T1用作计数时的计数脉冲由提供。 A. P3.5引脚B. 内部时钟频率 C. P3.4引脚D. 内部时钟频率12分频 二、 填空题 1. AT89C51有5个中断源,有个优先级。控制中断允许的特殊功能寄存器是,控制中断优先级的特殊功能寄存器是。 2. 外部中断1的中断入口地址为,定时器1的中断入口地址为。 3. AT89C51外部中断请求信号有电平触发方式和。在电平触发方式下,当采集到INT0、INT1为时,激活外部中断。 4. 要将外部中断INT0设置为电平触发方式,则应将位设置成。要将外部中断INT1设置成跳沿触发方式,则应将位设置为。 5. AT89C51有两个定时器/计数器,它们是由、、和4个专用的特殊寄存器构成的。 6. 当定时器/计数器T0申请中断时,T0的计满溢出标志位TF0为,当中断得到CPU响应后,TF0为。 7. 若IP=00010100B,则优先级最高者为,最低者为。 8. 定时和计数都是对进行计数,定时与计数的区别是。 9. 当定时器/计数器T0工作在计数模式时,计数脉冲来自于引脚。 10. 当时,定时器/计数器发出中断请求。 11. 设定时器/计数器T0工作在计数模式,工作方式2,TR0控制启停; 定时器/计数器T1工作在计时模式,工作方式1,TR1控制启停,那么,TMOD=。 12. 定时器/计数器的工作方式3是指将拆成两个独立的8位计数器。另一个定时器/计数器T1此时通常只用作。 13. 设单片机晶振频率为12MHz,利用定时器T0定时200μs,那么,采用工作方式0时的计数初值为,采用工作方式1时的计数初值为,采用工作方式2时的计数初值为。 14. 设单片机晶振频率为6MHz,利用定时器T0定时。在工作方式0下,最大定时时间是μs; 在工作方式1下,最大定时时间是μs; 在工作方式2下,最大定时时间是μs; 在工作方式3下,最大定时时间是μs。 三、 判断题 1. 定时器/计数器控制寄存器TCON只是控制定时器/计数器的。() 2. 设置中断允许寄存器IE=0x05,外部中断INT0、INT1能够正常中断。() 3. 低优先级中断服务程序可以被高优先级中断请求所中断,但是,高优先级中断服务程序不能被低优先级中断请求所中断。() 4. 一个中断请求得到响应后,不会被与它同优先级的中断请求所中断。() 5. 外部中断INT1的中断编号是1。() 6. 通过TMOD,可以设置定时器/计数器的4种工作方式。() 7. 定时器/计数器都是对输入脉冲进行计数的。() 8. 当TMOD中的GATE=1时,表示由两个信号控制定时器/计数器的启停。() 四、 简答题 1. 试叙述中断的全过程。 2. 中断优先级控制的原则是什么? 3. 说明中断服务函数与普通函数的不同之处。 4. 定时器/计数器用作定时器时,其计数脉冲由谁提供?定时时间与哪些因素有关? 5. 定时器/计数器用作计数器模式时,对外界输入脉冲的频率有何限制? 6. 定时器/计数器的工作方式2有什么特点?适用于哪些应用场合? 7. 如果采用的晶振的频率为3MHz,定时器/计数器工作在方式0、1、2下,其最大定时时间各为多少? 8. 用定时器/计数器测量某正单脉冲的宽度,采用何种方式可得到最大量程?若时钟频率为6MHz,求允许测量的最大脉冲宽度是多少? 9. 说明T0计满溢出标志位TF0是怎么置1与清0的? 10. AT89C51在使用定时器/计数器之前必须对它进行初始化,初始化的任务是什么? 五、 论述题 1. 一个中断请求被CPU响应的条件是什么? 2. 下面几种中断从高到低优先顺序的安排是否可行?如果可行,写出中断优先级寄存器IP的初始化值。如果不可行,请说明理由。 (1) T0,T1,INT0,INT1,串行中断。 (2) 串行中断,INT0,T0,INT1,T1。 (3) INT0,T1,INT1,T0,串行中断。 (4) INT0,INT1,串行中断,T0,T1。 (5) 串行中断,T0,INT0,INT1,T1。 (6) INT0,INT1,T0,串行中断,T1。 (7) INT0,T1,T0,INT1,串行中断。 3. 设单片机晶振频率为6MHz,利用定时器/计数器T0定时。在工作方式1下,最大定时时间约为130ms。现在需要定时1min,可以怎么实现? 4. 工作模式寄存器TMOD的低4位各位的作用是什么?怎么设置? 5. 定时器/计数器控制寄存器TCON在定时应用中起什么作用?怎么设置? 6. AT89C51用于中断允许控制的寄存器是什么?写出中断允许控制寄存器各位的符号及含义。中断允许控制寄存器是怎么控制中断允许的? 六、 程序设计题 1. 外部中断INT1为跳沿触发、高优先级的中断。试编写INT1的中断初始化程序段。 2. 设单片机晶振频率为6MHz,定时器/计数器T1工作在计时模式,工作方式2,TR1控制启停,产生200μs定时,采用中断方式。试编写T1的中断初始化程序段。 3. 设单片机晶振频率为12MHz,单片机INT0(P3.2)引脚连接一个按键S1,P0连接8个LED。编写控制程序,实现如下功能: 通过按键S1改变流水灯的流动方向; 使用软件延时方式控制流水灯的切换时间。 4. 设单片机晶振频率为12MHz,利用定时器/计数器T0中断,采用工作方式1定时,在P2.0输出频率为1Hz的方波。 5. 设单片机晶振频率为12MHz,利用定时器/计数器T0中断,采用工作方式2定时,在P2.0输出周期为500μs,占空比为4∶1的矩形波。