3.2中断的概念和应用-1-任务3.4中断的概念和应用3.4.1任务介绍中断和定时器是单片机中最重要的资源之一,中断功能的存在很大程度上提高了单片机处理外部或者内部事件的能力。什么是中断,我们从一个生活中的例程引入。你正在家中看书,突然电话铃响了,你放下书本,去接电话,和来电话的人交谈,然后放下电话,回来继续看你的书。这就是生活中的“中断”的现象,就是正常的工作过程被突如其来的事件打断了。本节的任务是:单片机外接两个两个发光二极管和一个按键,,其中一个发光二极管以0.5Hz的频率闪烁,另外一个发光二极管,按键每按下一次改变一下状态,按键用采用外部中断的方式。3.4.2知识准备1、中断的基本概念(1)单片机中为什么需要中断我们先根据之前学过的知识试着编写一下任务要求的程序,程序如下://......省略了程序开头部分while(1){LED1=1;//LED1灭DelayMs(1000);//延时1000msLED1=0;//LED1亮DelayMs(1000);//延时1000msif(KeyInput==0)//检测按键是否按下{DelayMs(10);//10ms延时消抖if(KeyInput==0)//再次判断按键是否按下{LED2=!LED2;//按键按下,LED2状态取反while(!KeyInput);//等待按键弹起}}}3.2中断的概念和应用-2-烧录到单片机后,我们发现程序运行的效果并非和我们想象中的一样,如果按键不按下,LED1闪烁正常,按键按下,LED1不再闪烁,直到按键弹起。LED2也并非是每次按键按下都改变状态,按键有的时候没有检测到。我们先来分析一下按键为什么没有检测到的原因。主程序中有两个任务,任务1:LED1以2Hz频率闪烁,任务2:按键按下LED2状态取反。这两个任务在大循环中顺序运行,即任务1执行完后,才能执行任务2。LED1闪烁一次需要2000ms(亮1000ms+灭1000ms),按键按下到弹起来大约需要200ms-500ms左右。如果程序刚开始执行任务1,这个时候按键也按下了,那么按键所对应的任务2必须等待任务1执行完了,才能执行。任务1执行完了,2000ms过后,再扫描按键,按键早就释放了,本次按键无效。我们的生活中也会遇到这样的问题,以接电话为例。你正在看着书,如果没有别的事情会一直看下去,这个时候电话响了,如果我们按照程序的思路,任务1执行完了,才能执行任务2,那么我们只有把书看完了,才能去接电话,这显然是不合理的。我们把所有需要处理的事件都放到大循环while(1)中去一个个的执行的方式是行不通的,一些紧急的事件必须立即处理,不能等待。中断就具有处理紧急事件的能力。(2)中断的响应过程正在看书,这是电话铃响了,在接电话之前,我们要把正在看的那一页书做个标记,接完电话后后我们按照之前的标记继续看书。单片机响应中断的过程和看书接电话的过程类似。中断事件产生后,首先要保存当前执行程序的地址,然后再去执行中断函数,中断函数执行完后,再从保存的地址处开始执行程序。(3)中断的种类传统的8051单片机一共有5个中断源(DIP封装的STC89C52有6个中断),它们的符号、名称和产生的条件分别解释如下:①:INT0:外部中断0,由P32端口引入,低电平或下降沿引起。②:INT1:外部中断1,由P33端口引入,低电平或下降沿引起。③:T0:定时/计数器0中断,由定时/计数器0溢出引起。④:T1:定时/计数器1中断,由定时/计数器1溢出引起。⑤:TI/RI:串行口中断,由串行口发送或者接受一帧数据引起。本节当中我们只关注两个外部中断,定时器和串口的中断在后面的章节会详细介绍。(4)中断优先级和嵌套在某些时刻,2个或者更多个中断同时到来,单片机应该响应哪一个中断呢?设想一下,你正在看书,电话铃响了,同时又有人按了门铃,你该先做那样呢?如果你正在等一个很重要的电话,你一般不会去理会门铃的,而反之,你正在等一个重要的客人,则可能就不会去理电话了。总之这里存在一个优先级的问题,单片机的5个中断也有优先级,即两个以上的3.2中断的概念和应用-3-中断同时触发,CPU先响应哪一个。另外还可能存在这样一种情况,你正在看书,电话铃响了,去接电话,在接电话的过程当中,这时又有人按门铃,我们的做法是先暂停通话,打开门,然后再接听电话,接听电话完后再继续看书。一个正在执行的中断任务被另外一个级别更高的中断任务打断,称之为中断的嵌套。51单片机的优先级有两大类:高优先级和低优先级,如果不对优先级做任何的设置,系统默认的是低优先级。在同类优先级中,也有一个先后顺序,称为自然优先级。在51单片机中自然优先级的顺序为,外部中断0定时/计数器0外部中断1定时/计数器1串口。在同类优先级中,当同时有几个中断到达,自然优先级高的中断会先得到响应,但不能实现中断的嵌套,例如,定时/计数器0和外中断0同为低优先级,当它们同时到来时,由于外部中断0定时/计数器0,系统先进入到外部中断0的程序,然后再执行定时/计数器0的中断程序。要想实现中断的嵌套,中断A能打断中断B的执行,则中断A和中断B不能在同一类型优先级中,中断A应设置为高优先级,中断B设置为低优先级。例如:串口中断在同类优先级中的排位是最低的,但如果把串口中断设置为高优先级,而其他中断设为低优先级,,则串口中断不仅可以在两个中断到来时优先执行,而且可以在别的中断正在运行时,打断别的中断转而执行串口中断。2、中断的寄存器配置51单片机中断系统框图可用图3.4.1来表示。图3.4.151单片机中断系统框图1IT0=0IT0=1INT0T0T1TXRXTCONIEEX0EAIPPX01111100000PSPT1PX1PT0SCON中断标志源允许总允许硬件查询矢量地址矢量地址自然优先级自然优先级IT1=0IT1=1INT1IE0TF0IE1TF1TIRIEX0EX1≥1ET1ES优先级高级中断请求PC低级中断请求PC3.2中断的概念和应用-4-中断的系统框图分为几个部分:①系统框图的前半部分是5个中断源及对应的触发标志。5个中断源分别是外部中断0(0INT)、定时器0(T0)、外部中断1(1INT)、定时器1(T1)和串口中断(TI或RI)。对应的触发标志分别为IE0、TF0、IE1、TF1和TI(RI),分别放在TCON和SCON寄存器当中,中断没有触发,这些中断触发标志位置0,中断触发,则对应的中断触发标志置1。②系统框图的后半部分是中断的优先级配置和中断的响应请求。5个中断的优先级配置位分别是PX0、PT0、PX1、PT1和PS,置1为高优先级,置0或者默认为低优先级,这些位在寄存器IP中。需要注意的是,这些位不可单独位寻址,举个例子:设置外部中断0的优先级为高优先级,不能在程序中,写成PX0=1,而应该是对寄存器IP配置,即IP=0x01。中断触发后,根据优先级的配置,向CPU申请响应。③系统框图的中间部分是中断的允许开关。前面部分中断触发后,要得到后面CPU的响应,必须把中间部分的开关合上去,即通常说的“开中断”。中断开关又分两级,即总开关EA和每一个中断源各自的开关(分别是EX0、ET0、EX1、ET1和ES),这些位的配置在于寄存器IE中,置0关中断,置1开中断,初始化为置0。这些位可以单独寻址,举例例子:开外部中断0,程序应该这样配置:IE寄存器和IP寄存器具体各个位的关系如表3.4.1和表3.4.2所示。表3.4.1IP寄存器和IE寄存器位配置表3、外部中断的特点和中断服务函数的编写51单片机有0INT和1INT两个外部中断源,分别由外部引脚P32和P33上的电平变化或状态变化作为中断触发信号。(1)外部中断触发方式51单片机的外部中断有两种触发方式:一种是电平触发方式,另外一种是下降沿触发方位序号D7D6D5D4D3D2D1D0IE(开关)EAESET1EX1ET0EX0IP(优先级)PSPT1PX1PT0PX0说明总开关串口定时器1外中断1定时器0外中断0EA=1;//开总中断EX0=1;//开外部中断03.2中断的概念和应用-5-式。低电平触发的特点是只要外中断输入引脚P32或P33保持低电平,将会一直产生中断申请。下降沿触发的特点是当检测到外中断输入引脚P32或P33由高电平跳变到低电平的瞬间时产生中断申请。外中断触发方式的选择在TCON寄存器中配置,如表3.4.3所示。表3.4.3TCON寄存器位配置表TCON寄存器中的高四位用于定时/计数器,低四位用于外中断。IE0和IT0属于外部中断0,IE1和IT1属于外中断1。IT0:外中断0触发方式选择位:当IT0=0,为低电平触发方式;当IT0=1,为下降沿触发方式。IE0:外中断0请求标志位,当触发中断时,IE0由‘0’变‘1’,中断结束后IE0自动清零。IT1、IE1同IT0、IE1使用方法相同。(2)中断服务函数的编写在讲解中断服务函数之前,我们先来了解一下中断现场的保护和恢复。术语过于专业,我们以之前讲过的看书接电话为例:看书类比于主程序在执行任务,突然之间接到一个电话,类比于产生了中断,在去接电话之前,需要把看到的那页纸张做个标记(把正在看的纸张折一下),给纸张做标记的动作就是中断现场保护,单片机在去处理中断前,也需要给主程序中的任务做个标记,记录主程序从哪一行暂停和当前运行变量的值。电话接完了,根据之前的书上的标记接着看书,单片机中断也是,处理完了中断任务后,CPU又从主程序被中断的哪一行接着运行,这个过程称为中断现场的恢复。我们在用keilC51(高级语言开发环境)编写中断服务程序时,不必考虑中断现场的保护和恢复,这是由于编译器在编译中断服务程序时,会在生成的目标代码中自动加入相应的中断现场保护和恢复的指令。在keilC51中,中断服务程序必须定义成一个特殊的函数,称为中断服务函数,函数按照以下格式定义:定时/计数器外中断位序号D7D6D5D4D3D2D1D0位符号TF1TR1TF0TR0IE1IT1IE0IT0说明定时器1溢出标志位定时器1运行控制位定时器0运行控制位定时器0运行控制位外中断1请求标志位外中断1触发方式选择位外中断0请求标志位外中断0触发方式选择位void函数名()interrupt中断号using工作组{中断服务程序}3.2中断的概念和应用-6-中断服务函数的前半部分与普通函数的定义是一样的,函数类型函数名()。不同之处在于中断服务函数多了一个关键字interrupt。interrupt用来声明该函数为中断服务函数,Interrupt后是中断向量号,CPU会根据中断向量号去计算该中断在中断向量表里的位置,然后跳到中断服务函数里,每一个中断源都会有一个特定的中断向量号如表3.4.4所示。最后面的“using工作组”是指这个中断函数使用单片机内存中4个工作寄存器中的哪一组。C51编译器在编译程序时自动分配工作组,我们在编写程序时通常省略“using工作组”。表3.4.4中断号三、任务实施有了以上的知识准备,我们来完成本节的任务。按键接单片机的P3.2引脚(外部中断0),按键每按下一次,P3.2的引脚的电平从高电平到低电平变化一次,我们可以利用外部中断0的下降沿触发来完成按键的检测。程序如下:中断名称外部中断0定时器0中断外部中断1定器1中断串口中断中断号01234#includereg52.h#defineucharunsignedchar#defienuintunsignedintsbitLED1=P1^0;sbitLED2=P1^1;//两位LED分别接P10和P11sbitKeyInput=P3^2;//按键接P3.2引脚//ms级延时子函数voidDelayMs(uintxms){uinti,j;for(i=0;ixms;i++)for(j=0;j122;j++);}//主函数voidmain(void){IT0=1;//下降沿触发外部中断EX0=1;//使能外部中断0EA=1;//使能总中断while(1)3.2中断的概念和应用-7-程序