计算机中断

什么是中断
    中断是计算机中的一个十分重要的概念,在现代计算机中毫无例外地都要采用中断技术。什么是中断呢?可以举一个日常生活中的例子来说明,假如你正在给朋友写信,电话铃响了。这时,你放下手中的笔,去接电话。通话完毕,再继续写信。这个例子就表现了中断及其处理过程:电话铃声使你暂时中止当前的工作,而去处理更为急需处理的事情(接电话),把急需处理的事情处理完毕之后,再回头来继续原来的事情。在这个例子中,电话铃声称为“中断请求”,你暂停写信去接电话叫作“中断响应”,接电话的过程就是“中断处理”。相应地,在计算机执行程序的过程中,由于出现某个特殊情况(或称为“事件”),使得暂时中止现行程序,而转去执行处理这一事件的处理程序,处理完毕之后再回到原来程序的中断点继续向下执行,这个过程就是中断。


计算机为什么要采用中断
     为了说明这个问题,再举一例子。假设你有一个朋友来拜访你,但是由于不知道何时到达,你只能在大门等待,于是什么事情也干不了。如果在门口装一个门铃,你就不必在门口等待而去干其它的工作,朋友来了按门铃通知你,你这时才中断你的工作去开门,这样就避免等待和浪费时间。计算机也是一样,例如打印输出,CPU传送数据的速度高,而打印机打印的速度低,如果不采用中断技术,CPU将经常处于等待状态,效率极低。而采用了中断方式,CPU可以进行其它的工作,只在打印机缓冲区中的当前内容打印完毕发出中断请求之后,才予以响应,暂时中断当前工作转去执行向缓冲区传送数据,传送完成后又返回执行原来的程序。这样就大大地提高了计算机系统的效率。


什么是中断的优先级
     我们仍然可以举例说明中断优先级的概念。在上面的例子中,如果在电话铃响的同时,门铃也响了,那么你将在“接电话”和“开门”这两个中断请求中选择,先响应哪一个请求。这就有一个谁优先的问题。如果“开门”比“接电话”重要(或者说“开门”比“接电话”的优先级高),那么就应该先开门,然后再接电话,接完电话后再回头来继续写信。这就是说,当同时有多个中断请求时,应该先响应优先级较高的中断请求。
     此外,如果在响应一个中断,执行中断处理的过程中,又有新的中断事件发生而发出了中断请求,应该如何处理也取决于中断事件的优先级。当新发生的中断事件的优先级高于正在处理的中断事件时,又将中止当前的中断处理程序,转去处理新发生的中断事件,处理完毕才返回原来的中断处理。在上面的例子中,我们假设“开门”比“接电话”的优先级高。在你写信时,电话铃响了,你去接电话,在通话的过程中,门铃又响了。因为“开门”的优先级高,你只能让通话的对方稍等,放下电话去开门。开门之后再回头继续接电话,通话完毕再回去继续写信。而如果“开门”比“接电话”的优先级低,那么在通话的过程中门铃响了也可以不予理睬,通话结束再去开门。当然,在日常生活中,谁也不会为“开门”和“接电话”规定一个优先级别的高低。但是在计算机中,各种中断事件很多,其优先级都有规定,否则就会乱套。在计算机中,中断事件的优先级是根据事件的实时性、重要性和软件处理的方便性来安排的。


中断的屏蔽
     中断屏蔽也是一个十分重要的功能,所谓中断屏幕蔽是指通过设置相应的中断屏蔽位,禁止响应某个中断。这样作的目的,是保证在执行一些重要的程序中不响应中断,以免造成迟缓而引起错误。例如,在系统启动执行初始化程序时,就屏蔽键盘中断,使初始化程序能够顺利进行。这时,敲任何键,都不会响应。当然对于一些重要的中断是不能屏蔽的,例如重新启动、电源故障、内存出错、总线出错等影响整个系统工作的中断是不能屏蔽的。因此,从中断是否可以被屏蔽来看,可分为可屏蔽中断和不可屏蔽中断两类。


中断是怎样分类的
     产生中断请求的设备或事件称为“中断源”。从中断源来看,中断一般可分为三类:
     (1) 由计算机硬件异常或故障引起的中断,也称为内部异常中断。
     (2) 由程序中执行了中断指令引起的中断,也称为软中断。
     (3) 外部设备(如输入输出设备)请求引起的中断,也称为外部中断或I/O中断。
     在这三类中断中,外部中断我们接触得最多。下面我们来作进一步的介绍。


中断控制器和中断通道
     因为每个设备都要使用中断,每个设备也就需要一个传送中断请求的通道。而CPU中只有一条接收中断请求的引脚,因此需要有一个机构来收集各个设备产生的各种中断请求,并按优先级排列送给CPU。这个机构称为中断控制器。早期的中断控制器是一片8259集成芯片,可以接收8个中断请求信号,也就是可以有8个中断通道。PC机允许使用15个中断通道,因此需要两片8259芯片。现在的微机仍然维持了这个结构,不过8259芯片已不是独立的芯片,而被进一步集成到其它的大规模芯片中了。
     两片8259之间用级联的方法连接起来,即一片8259的输出连接到另一片8259的输入端。因此实际可以使用的中断通道只有15个。

Two8259ChipTogether

图1: 8259级联图(级联输入端为IRQ2)

IRQTable

图2:中断通道所对应的设备

    上图表示了中断控制器和各个中断通道号对应的外部设备。
    由于每个设备都要占用一个中断通道,如果有两个或两个以上的设备占用了相同的通道时就会发生冲突,使得设备不能正常工作甚至死机。因此在安装新的设备时,一定要选择那些还没有被占用(保留)的中断通道,否则就会引起冲突。选择中断通道一般是通过改变适配卡上的跳线来实现的。很多微机在安装声卡或电影卡时没有正确地选择好中断通道,造成冲突后不能工作。对于有即插即用功能的微机和适配卡,能够自动地选择未被占用的通道,就不需要我们去设置了。

 

《嵌入式系统软件教程》中对于中断的定义(Chapter3 高级硬件基础 / P35)

    我们都知道,微处理器可以被中断,也就是说停止它正在执行的程序转而去执行其他程序,即中断程序。通知微处理器去运行中断程序的信号称为中断请求(或IRQ)。大部分微处理器都有几个外部中断请求的输入引脚。这些引脚与I/O设备中断请求的输入引脚相连就可以中断微处理器。

    中断请求信号一般被设置为低位,I/O设备上的中断请求引脚通常可以开放式连接,使几个中断请求引脚可以共享微处理器上的一个中断请求引脚。如图3-12所示。I/O设备A可以通过IRQ0 信号中断处理器;I/O设备B可以通过IRQ1 中断处理器;I/O设备C和D通过IRQ2 中断处理器。

    与DMA通道响应DMAREQ信号类似,微处理器会响应中断输入,这些输入可以是边沿触发,也可以是电平触发。

 

    在嵌入式软件设计中,必须考虑快速响应外部事件。例如,如果用户按下了要求知道2号油罐中有多少汽油的按键,即使此时地下油罐监视器正在忙于计算6号油罐中装了多少汽油,也必须迅速地做出响应。
    解决响应问题的第一个方法就是使用中断,中断迫使嵌入式系统中的微处理器挂起当前的任务,转而执行中断事件的处理代码。

    中断是从一个硬件信号开始的,大多数的I/O芯片,例如驱动串口或网络接口的I/O芯片,都需要注意某些事件的发生。例如,一个串口芯片收到来自串口的字符时,串口芯片需要微处理器把该字符从串口中存储该字符的位置读到内存中的某个地方。类似的,当串口芯片传送完一个字符后,它需要微处理器给它发送下一个需要传送的字符。
    每个这样的芯片都有判断芯片什么时候需要服务的引脚。硬件工程师把这个引脚放在了微处理器上,称为中断请求或IRQ。这样,微处理器通过中断请求就能知道电路中是否有其他哪些芯片需要服务。绝大多数微处理器都有几个这样的引脚,因此不同的芯片可以连接到微处理器上请求微处理器的服务。

任务代码(task code)

    指不属于中断程序的代码。中断发生时,微处理器挂起任务代码,执行中断程序。中断程序的代码执行到RETURN时,微处理器回到任务代码继续往下执行。
    ISR(Interrupt Service Routine)中断服务例程,Interrupt handler中断处理器。

    中断程序开始时要把所有的寄存器压栈,这个过程叫保存上下文;中断程序结束后的弹栈,这个过程叫恢复上下文。如果在中断发生的时候,不保存、不保存上下文,则会导致一些讨厌的错误。


禁止中断的方法:
    首先,即使在I/O芯片需要向微处理器发出中断请求的时候,大多数I/O芯片也允许程序来禁止中断。
    其次,大多数微处理器允许用户程序制定忽略哪一个芯片引脚上的中断请求信号。多数情况下,用户程序只需要往微处理中特定的寄存器写入一定的值就可以决定微处理应该响应哪些中断请求,忽略哪些中断请求。

    NMI :微处理器上的某个输入引脚,该引脚产生的终端不可禁止,被称为不可屏蔽中断。无法禁止不可屏蔽中断,则相关的中断程序就不能和任务代码共享任何数据。正因为如此,不可屏蔽中断常常用于那些超出常规处理范围的事件。例如,对电源故障等类似的灾难性事件,就只能用非屏蔽中断来让系统做出响应。

微处理器是如何禁止中断和允许中断的?
    所有的中断请求信号都被分配一个优先级,并允许程序制定最低优先级中断的优先级,以便微处理器对最低优先级中断能够及时响应。
    想禁止所有中断(不可屏蔽中断除外),只需把可接受的优先级设置的比所有中断的优先级高就可以了;相反,如果要允许所有中断,则把可以接受的优先级设置得比所有中断的优先级都低就可以了。如果把可接受的优先级设置得适中一点,则可以有选择地允许一部分的中断了。另外,这种优先级机制有时还适用于允许和禁止单个的中断。


中断优先级
    为使系统能及时响应并处理发生的所有中断,系统根据引起中断事件的重要性和紧迫程度,硬件将中断源分为若干个级别,称作中断优先级。

问答:
中断发生时,微处理器怎么知道去哪里找中断程序呢?
    可以从微处理器的用户手册得到答案。一些微处理器假定中断服务程序在一个固定的位置。比较典型的一种方法是在内存在某个位置存放一张表,该表的内容就是中断程序的地址,即中断向量。某个中断产生时,微处理器会在中断向量表中查找中断程序的地址。当然,你必须负责很好地建立中断向量表。
使用中断向量表的微处理器如何知道中断向量表的位置?
    通常和微处理器有关,在一些微处理器中,中断向量表总在同一位置,例如Intel的80186,表地址在0x00000处。还有一些微处理器会通过一些方法把中断向量表的地址提供给用户程序。
两个中断同时产生,微处理器会优先执行哪一个中断程序呢?
    优先执行优先级高中断的中断程序。
一个中断请求信号是否可以中断另一个中断程序?
    和平台有关,大多数而言,可以。某些处理器中,必须在中断程序中加入一条或两条指令才能允许中断嵌套。高优先级的中断能够中断低优先级的中断程序,反过来则不行。
中断被禁止的时候发生中断请求会怎么样?
    大多数时候,微处理器会记下发出请求的中断,等到允许中断的时候就会跳转去执行中断程序。如果中断被禁止时有多个中断发出请求信号,微处理器会在中断允许时按优先级顺序响应这些中断。因此,中断并没有被真正地禁止,而是被推迟了。
忘记恢复被禁止的中断会如何?
    不会执行任何中断程序,任何跟中断程序有关的处理都会慢慢停下来。

禁止/允许一个已经被禁止/允许的中断会如何?

    不会发生任何事情
微处理器启动的时候中断被禁止还是允许?

    被禁止
是否允许用C语言写中断程序?

    通常是可以的。但是用汇编语言写中断程序的一个原因是:汇编语言写的程序速度快于C语言的程序。如果速度不是问题,可以考虑用C语言来编写中断程序。
一条指令在执行的过程中,微处理器能被中断吗?

    通常是不行的。绝大多数情况下,微处理器会在执行完当前指令后才跳转到中断程序。例外的情况是移动大量数据的单条指令,,可能移动上千字节数据的单条指令,在传送完一个字节或一个字的时候就能被中断,直到中断程序返回,该指令会从被打断的地方开始继续传送数据。

 

共享数据问题:

 

代码1:

static int iTemperatures[2];

void interrupt vReadTemperatures (void)
{
	iTemperatures[0] = // read temperature value from memory
	iTemperatures[1] = // read temperature value from memory
}	

void main(void)
{
	int iTemp0, iTemp1;

	while(TRUE)
	{
		iTemp0 = iTemperatures[0];
		iTemp1 = iTemperatures[1];
		if(iTemp0 != iTemp1)
			// Alarm Function
	}
}

 上述程序的致命缺点:

    假定某个时候两个温度值都是73,则iTemperatures数组中的元素值都是73。假设微处理器执行完

iTemp0 = iTemperatures[0];

后中断产生,把温度改变为74。中断程序会把数组iTemperatures中的元素值都改成74。中断程序执行完后,微处理器接着执行

iTemp1 = iTemperatures[1];

iTemp1的值为赋为74,因为iTemp0=73, iTemp1=74,系统会误发出警报。

 

更难的共享数据问题:

static int iTemperatures[2];

void interrupt vReadTemperatures (void)
{
	iTemperatures[0] = // read temperature value from memory
	iTemperatures[1] = // read temperature value from memory
}	

void main(void)
{
	while(TRUE)
	{
		if(iTemperature[0] != iTemperature[1])
			// Alarm
	}
}

     看似没有问题,但是问题的关键在于比较iTemperature[0]和iTemperature[1]的那条语句可以被中断。C语言里,单条语句是能被中断的,这是因为大多数C语言的语句都会被编译器翻译为多条汇编语言指令。例如,比较iTemperature[0]和iTemperature[1]的那条语句会被翻译为:

...
    MOVE R1, (iTemperature[0])
    MOVE R2, (iTemperature[1])
    SUBTRACT  R1, R2
    JCOND ZERO, TEMPERATURES_OK
...
    ; Alarm Code
...

TEMPERATURES_OK:
...

     由此看来,这个程序的问题和第一个的问题实质上是一样的。

    代码问题所在:中断程序和任务代码共享了数组iTemperature,如果中断发生在main程序正在使用iTemperature时,共享数据问题就会出现。

 

解决共享数据问题:

static int iTemperatures[2];

void interrupt vReadTemperatures (void)
{
	iTemperatures[0] = // read temperature value from memory
	iTemperatures[1] = // read temperature value from memory
}	

void main(void)
{
	int iTemp0, iTemp1;

	while(TRUE)
	{
        disable ();
		iTemp0 = iTemperatures[0];
		iTemp1 = iTemperatures[1];
                enable();
		if(iTemp0 != iTemp1)
			// Alarm
	}
}

 对应的汇编代码如下:

...
   DI            ;Disable Interrupt when using iTemperature
    MOVE R1, (iTemperature[0])
    MOVE R2, (iTemperature[1])
     EI            ; Enable Interrupt after using iTemperature
    SUBTRACT  R1, R2
    JCOND ZERO, TEMPERATURES_OK
...
    ; Alarm Code
...

TEMPERATURES_OK:
...

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值