嵌入式系统/中断
有时系统中会发生一些事情,而处理器却无法及时处理。实际上,有时系统会发生一些需要立即处理的事情。试想一下,当你坐在电脑前,按下键盘上的按键,但电脑没有任何反应?
也许处理器正忙于处理其他任务,并没有检查你是否按下了任何按键。解决这个问题的方法是使用一种称为“中断”的技术。中断是指引起微处理器停止当前任务,并优先处理一项高优先级任务的事件。中断处理完成后,微处理器会返回到之前正在执行的任务。这样一来,我们就可以确保高优先级输入永远不会被忽略。
中断分为两种类型:硬件中断和软件中断。软件中断是由软件使用特定指令触发的。硬件中断是由微控制器外部的周边设备触发的。例如,你的嵌入式系统可能包含一个计时器,它每秒向控制器发送一个脉冲信号。你的微控制器将等待接收此脉冲,当脉冲到达时,将触发一个中断来处理信号。
中断服务程序 (ISR) 是处理中断请求的程序代码部分。当触发中断(无论是硬件中断还是软件中断)时,处理器会停止当前任务,将指令指针移动到 ISR,然后继续执行。当 ISR 完成时,处理器会返回到中断前的执行位置。
许多嵌入式系统被称为**中断驱动系统**,因为大多数处理都在 ISR 中进行,嵌入式系统大部分时间都处于低功耗模式。
有些人将 ISR 分为两部分:上半部分(快速中断处理程序,一级中断处理程序 (FLIH))和下半部分(慢速中断处理程序,二级中断处理程序 (SLIH))。上半部分是 ISR 中较快的一部分,它应该快速存储关于中断的最小信息,并在稍后时间安排较慢的下半部分执行。
我们将在 中断体系结构 中讨论双层中断处理和其他编写中断处理程序的方法。
“中断向量表”是所有中断服务程序的列表。它位于程序内存中的固定位置。
(一些处理器期望中断向量表是一系列“调用”指令,每个指令后面跟着 ISR 的地址。其他处理器期望中断向量表只包含 ISR 的地址。)
你必须确保中断向量表中的每个条目都填充了某个实际 ISR 的地址,即使这意味着让大多数条目指向“不执行任何操作并从中断返回”的 ISR。
PIC18 和 PIC16 系列处理器只有一个中断处理程序,一个全局中断使能位,以及中断硬件中的一组位。每个可能的中断源在中断硬件中都有一对位——一个“标志”位,当硬件需要处理时被置位,就像它挥舞着旗帜试图引起注意,以及一个“使能”位,控制处理器是否忽略该标志,或者停止所有操作并运行中断处理程序。(令人困惑的是,有些人将这两个位都称为“标志”——在本节中,我们将“请求处理”位称为标志位,将“忽略或不忽略”位称为使能位)。
当 8 位 PICmicro(PIC18 或 PIC16)发生中断时,硬件会清除全局中断使能位,然后开始运行唯一的中断处理程序。中断处理程序软件必须以某种方式检查所有可能导致中断的事件——通常是逐个检查每个中断标志——并处理每个事件(如果有必要)。
680x0、x86、dsPIC、PIC24 和许多其他处理器都有多个中断向量。当某些硬件请求处理时,硬件会向量到并运行针对该特定硬件部分的特定中断处理程序。
许多人使用 C 语言编写中断程序。使用 gcc
的程序员声明中断处理程序的方式与声明普通函数非常类似,如下所示:[1]
void __attribute__ ((interrupt)) universal_handler ();
遗憾的是,没有标准的方法可以在可移植的 C 语言中编写中断处理程序。每个 C 编译器似乎都使用自己的关键字,与任何其他 C 编译器的关键字都不兼容。即使使用 gcc,常用的中断声明也会因处理器而异。[2][3]
其他程序员使用不支持直接在 C 语言中编写中断处理程序的 C 编译器。他们被迫用汇编语言编写中断处理程序,手动完成编译器为前一组人所做的事情。
中断程序通常以一堆模板代码开头,这些代码将状态寄存器和其他内容压入堆栈,并以另一堆模板代码结尾,用于恢复所有这些内容,以便被中断的代码可以从它停止的地方继续执行。这些模板代码在不同的处理器家族中差别很大——并且与正常的 调用约定 前导和后导代码有一些关键区别。
编译器(或汇编程序员)在中断向量表中写入指向该中断处理程序的指针。
一个非常常见的问题是在中断程序中执行“太多”操作。遗憾的是,症状通常只在两个不同的中断程序几乎同时触发时才会出现,从而导致难以调试的间歇性错误以及许多相互指责。不幸的是,编写了一个中断程序的人指出,他的程序单独运行时工作正常,而编写了另一个中断程序的人指出,他的程序单独运行时工作正常,但他们经常互相指责,当这两个中断同时发生时出现的错误。中断程序(可能是 UART 中断处理程序,但也可能是其他看似无关的中断程序)执行时间“过长”的一个常见症状是丢失了一些,但不是全部,通过 UART 传入的字符流中的字符。[4]
由于很难计算中断处理程序需要多少时间,因此通常直接测量中断处理程序实际需要多少时间。一种流行的调试技术是编写中断处理程序,使中断处理程序在每个中断程序的开始处将测试引脚置位为高电平,并在每个中断程序的结束处将测试引脚置位为低电平。连接到该引脚的示波器将显示该中断处理程序的实际执行时间。[4]