中断概念 : 计算机执行某程序时,发生了紧急事件或有特殊请求,CPU暂停某程序的执行, 转而去处理上述事件或请求,处理完毕后再重新执行某程序的过程叫做中断。
数据的输入/输出传送方式:
(1)无条件传送方式: 一方对另一方来说总是准备好的。
(2)查询传送方式(LOOK UP): 传送前一方先查询另一方的状态,若已经准备好就传送,否则就继续查询/等待。
(3)中断传送方式(IRQ): 一方通过申请中断的方式与另一方进行数据传送。
(4)直接存储器存取方式(DMA): 双方直接通过总线传送数据, 不经CPU中转。适用于数据量大高速通讯的设备不占用CPU时间。
中断传送方式特点:
数据传送的双方平时各自做自己的工作,一旦甲方要求与乙方进行数据传送,就主动发出信号提出申请,乙方接到申请后若同意传送,安排好当前的工作,再响应与甲方发生数据传送。完事后,回去继续做打断前的工作。
引起CPU中断的根源,称为中断源。
中断源向CPU提出的中断请求。CPU暂时中断原来的事务A,转去处理事件B。
对事件B处理完毕后,再回到原来被中断的地方(即断点),称为中断返回。
实现上述中断功能的部件称为中断系统(中断机构)。
中断功能强弱是计算机性能优劣的重要标志
提高CPU效率
解决速度矛盾
实现并行工作
应付突发事件……
51子系列允许5个中断源:
外部中断源(2个):
INT0——由P3.2端口线引入,低电平或下降沿引起。
INT1——由P3.3端口线引入,低电平或下降沿引起。
这两个外部中断源标志和它们的触发方式控制位由特殊功能寄存器TCON的低4位控制。
内部中断源(3个):
T0——定时器/计数器0中断,由T0回零溢出引起。
T1——定时器/计数器1中断,由T1回零溢出引起。
TI/RI——串行I/O中断,串行端口完成一帧字符发送/接收后引起。
这3个内部中断源的控制位分别锁存在特殊功能寄存器TCON和SCON中。
51的中断系统有5个中断源,2个优先级,可实现二级中断嵌套
1、中断请求标志TCON(88H)可位寻址
TCON:Timer控制寄存器,低4位管理外部中断
作用:设置外部中断触发方式,标注外部中断请求。
IE0/IE1:外部中断申请标志位:
=0:没有外部中断申请;=1:有外部中断申请。
IT0/IT1:外部中断请求的触发方式选择位:
=0:在INT0/INT1端申请中断的信号低电平有效;
=1:在INT0/INT1端申请中断的信号负跳变有效(由高跳变到低)。
外部中断及中断请求的撤除
低电平/负脉冲→INT0/INT1引脚可触发中断
IT0/IT1 =0 时,INT0/INT1是低电平有效;
IT0/IT1 =1 时,INT0/INT1是负跳变有效。
低电平触发 引脚上的低电平须持续到中断发生。若中断返回前仍未及时撤除低电平,将再次中断。
负脉冲触发 CPU在前一机器周期采到INT0/INT1引脚为高,后一机器周期采到为低才认为是一次中断请求。CPU 可记忆申请、可自动撤除中断申请。
中断允许控制寄存器IE(可位寻址)(A8H)
作用:CPU对中断系统所有中断以及某个中断源的开放和屏蔽是由中断允许寄存器IE控制的。
EA , CPU中断允许(总允许)位; =0 时禁止全部中断;=1 时允许中断。
ES,串行口中断允许位;=0 时禁止中断; =1 时允许中断。
ET1,定时/计数器T1中断允许位;=0 时禁止中断; =1 时允许中断。
EX1,外部中断1允许位;=0 时禁止中断; =1 时允许中断。
ET0,定时/计数器T0中断允许位;=0 时禁止中断; =1 时允许中断。
EX0,外部中断0允许位; =0 时禁止中断; =1 时允许中断。
中断优先级控制寄存器IP (B8H) 可位寻址
PX0/PX1:INT0/1优先级控制位: =0 时属低优先级; =1 时属高优先级。
PT0/PT1:T0/1中断优先级控制位: =0 时属低优先级;=1 时属高优先级。
PS1:串行口中断优先级控制位: =0 时属低优先级; =1 时属高优先级
中断优先级处理原则
对同时发生多个中断申请时:
☞不同优先级的中断同时申请(很难遇到) ——先高后低
☞正处理低优先级中断又接到高级别中断 ——高打断低
☞正处理高优先级中断又接到低级别中断 ——高不理低
☞相同优先级的中断同时申请(很难遇到) ——按序执行
单片机同优先级中内部查询顺序
中断响应条件
(1)此中断源的中断允许位为1。 如外部中断:EX0 = 1; //开外部中断0
(2)中断源有中断请求。 IT0 = 0; //低电平触发
(3)总中断CPU中断打开(EA = 1)。 EA=1;//开总中断
中断处理函数:
void int0 interrupt 0 //说明是中断服务函数,查询方式优先级是0
{
}
定时器中断实现让8个LED灯亮200MS灭200MS
#include <reg52.h> #define uchar unsigned char #define uint unsigned int uint count; void delay(uint z) { uint x,y; for(x = z; x > 0; x--) for(y = 114; y > 0 ; y--); } /*中断服务特殊功能寄存器配置*/ void init() { TMOD = 0x01; //定时器16为计数工作模式 TH0 =0x4b; TL0 =0xfd; //50ms ET0 = 1; //开定时器0中断 TR0 = 1;//启动定时器0 EA = 1; //开总中断 } void main() { init(); while(1); } /*中断服务程序*/ void timer0() interrupt 1 { TH0 =0x4b; TL0 =0xfd; //50ms count++; if (count == 4) { P1 = ~P1; count = 0; } }
使用定时器1中断让8个LED循环右移,间隔500ms,同时使用定时器0中断方式让数码管前2位间隔1000ms从0显示到60,如果有外部中断产生则停止数码管走数 (外部中断0低电平触发方式)
#include <reg52.h> #include <intrins.h> #define uchar unsigned char #define uint unsigned int sbit we = P2^7; sbit du = P2^6; uchar count0,count1;//全局变量 存储定时器加一计数器溢出次数 uchar temp0,temp1 = 0x7f; //temp0负责数码管的值,temp1负责流水灯的值 uchar code leddata[]={ 0x3F, //"0" 0x06, //"1" 0x5B, //"2" 0x4F, //"3" 0x66, //"4" 0x6D, //"5" 0x7D, //"6" 0x07, //"7" 0x7F, //"8" 0x6F, //"9" 0x77, //"A" 0x7C, //"B" 0x39, //"C" 0x5E, //"D" 0x79, //"E" 0x71, //"F" 0x76, //"H" 0x38, //"L" 0x37, //"n" 0x3E, //"u" 0x73, //"P" 0x5C, //"o" 0x40, //"-" 0x00, //熄灭 0x00 //自定义 }; void delay(uint z) //1MS延时 { uint x,y; for(x = z; x > 0; x--) for(y = 114; y > 0 ; y--); } void display(uchar i) //数码管显示函数 { uchar shi,ge; shi = i / 10; //求模 ge = i % 10; //求余 P0 = 0xff; //清除段码 we = 1; P0 = 0xfe; //点亮第一位数码管 we = 0; du = 1; P0 = leddata[shi]; du = 0; delay(1); P0 = 0xff; //清除段码 we = 1; P0 = 0xfd; //点亮第二位数码管 we = 0; du = 1; P0 = leddata[ge]; du = 0; delay(1); } /*中断服务特殊功能寄存器配置*/ void init() { TMOD = 0x11; //定时器T1/T0 16为计数工作模式 TH1 = TH0 = 0x4b; TL1 = TL0 = 0xfd; //T1/T0 定时50ms ET1 = ET0 = 1; //开T1/T0中断 TR1 = TR0 = 1; //启动T1/T0 EX0 = 1; //开外部中断0 IT0 = 0; //外部中断0为低电平触发 EA = 1; //开总中断 } void main() { init(); //调用配置函数 while(1) { display(temp0);//数码管显示 } } void int0() interrupt 0 //外部中断0,中断服务程序 { TR0 = 0; //关闭定时器0 } /*定时器0中断服务程序*/ void timer0() interrupt 1 //T0内部查询顺序1 { TH0 = 0x4b; TL0 = 0xfd; //定时器0再次放初值 50ms count0++; if (count0 == 20) { count0 = 0; temp0++; if (temp0 > 60) { temp0 = 0; } } } /*定时器1中断服务程序*/ void timer1() interrupt 3 //T1内部查询顺序3 { TH1 = 0x4b; TL1 = 0xfd; //定时器1再次放初值 50ms count1++; if (count1 == 10) { count1 = 0; P1 = temp1; temp1 = _cror_(temp1,1);//循环右移一次 } }