在正常的情况下,是我们的主程序在运行,也就是我们的任务在运行,假设我们的主程序运行到某个地方的时候,产生了中断请求,产生了中断请求以后,CPU来响应这个中断,它在响应这个中断之前呢,首先要做一件事就是现场的保护,这个很好理解,为什么这样呢?
因为当我们在执行完中断函数以后,我们还有退回到原来的主函数中去,开始接着往下执行,那这样的话,必须保护这个现场,如果不保护这个现场,我们以后从中断函数退出的时候,那捏怎么知道从什么地方执行呢?
所以,在这里,我们中断函数以后,要进行一个现场的保护。现场保护要做的是什么事情呢?
实际上就是保护CPU集成器,现场保护以后,CPU就转入中断函数执行,这个时候,就执行中断,执行中断也叫做ISR,执行完ISR以后,接下来我们要回到主程序执行,那它们之间的过程刚好是个相反的过程。刚刚我们进行了一个现场保护,那么现在我们要进行一个现场恢复,恢复完现场以后,接下来我们要干的事情就是执行主程序,这个是我们整个中断的过程。
1)中断延迟
中断延迟指的是,从产生中断开始,到执行第一条中断函数,这个时间被称作中断延迟时间。也就是说,从这一时刻,我开始产生中断请求,到另一个时刻,我才执行中断函数,那么这段时间,就被称做中断延迟。在这个中断延迟中,它都干了些什么事情,实际上就是一个CPU的现场保护。
2)中断响应
比如说,某一个事件产生了,那件产生了多长时间以后才会来响应这个事件,这个就叫做中断响应过程,中断响应和中断延迟是有一定的区别的。我们刚刚说中断延迟是从产生到延迟到执行第一条中断函数服务,而中断响应指的是产生中的请求然后到对这个中断进行处理,这个时间叫做中断响应。
3)中断恢复
中断恢复指的是这个中断函数执行完毕以后到我们的主程序去执行这一段时间就是中断恢复的时间。
在我们不带操作系统的开发当中,也就是逻辑开发当中,我们中断延迟和中断响应是一样的。假设我们跑了操作系统以后,跑了一个OS以后,我们看一下这个会变成什么样。
首先这个中断延迟还是一样的,那我们的这个主程序就相当于某个任务,这个任务在运行的过程中,产生了一个中断,产生了一个中断以后,还是CPU对现场进行一个保护,CPU保护完了以后,再进入我们的ISR,ISR执行完毕以后,接下来我们就退出,也就是中断恢复。
接下来我们来看一下这个过程,首先对于一个中断延迟,中断延迟指的还是中断请求以后,然后到第一条中断函数指令的时间。中断响应指的是中断服务函数执行以后,我们中断申请以后开始来处理这个中断,这个叫做中断响应。那在os也就是跑了中断系统以后,我们在中断函数中执行的第一条代码时这个代码OS-IntEnter();这个函数有两个作用,第一个作用是告诉CPU我进入了中断服务,第二个作用是告诉CPU当前中断嵌套函数的层数是多少,比如说,在这个中断执行的过程中,又有一个优先级比它高的中断把它打断了,那这个时候,CPU会跑过去执行优先级较高的中断,在优先级较高的中断中,我们也来执行了OS-IntEnter(),这个时候CPU会根据OS-IntEnter()执行的次数,来判断我们当前中断嵌套函数的层数,这个是这个中断函数的过程。我们可以看到,在加了这个操作系统以后,我们很多时候执行这个函数,那这个时候,中断延迟,中断响应的时间,就变成了中断延迟时间加上一个OS-IntEnter()这个函数执行的时间,这段时间叫做中断响应。
接下来是中断恢复,中断恢复和我们这个不带操作系统的也是有点区别的,首先,在中断恢复的时候,我们首先执行的指令是OS-IntExit(),这个函数也是有两个作用,第一个作用是告诉CPU我现在退出这个中断了,那出这个中断以后,我们是不是要跑去执行这个任务呢?那不一定,为什么呢?比如说,假设这里有一个中断嵌套,也就是这个中断打断的是上一个中断,那当这个中断退出以后,它就不能去执行任务,为什么呢?因为有别的中断还被它嵌套着,所以它要去执行上一个中断函数,当这个中断执行完了,它才会去执行任务。那也就是说,我们在中断恢复的时候,执行的是这个函数OS-IntExit(),那这个时候,它中断恢复的时间就变成OS-IntExit()它执行的时间,加上中断执行的时间,这是我们整个中断恢复的时间。
那在这里,有可能就有人来问了,这两个函数执行的时间有多长呢?那我们首先来看一下这两个函数,这两个函数实际上本质是由3个代码,第一个代码是关中断,第二个代码是让一个全局变量加1,第三个代码是开中断。那我们这里为什么要关中断和开中断呢?因为让这个变量加1是属于这个临界段代码,那我们在以前讲过,在对临界段代码操作的时候,必须关中断和开中断,这样保护。实际上,在这里呢,我们也就是有一个中断计数器,比如叫做ISRCounter,这个全局变量初始化为0,当进入中断一次,我们调用这个函数:OS-IntEnter(),在这个过程中,我们把这个变量加1,就变成1了,当退出这个中断,执行中断函数:OS-IntExit(),那在这个函数中,我们让这个变量减1,那我们可以看到,初中断加1,表明我们处于一个中断,初中断减1,表明我们当前不再处于中断。
那如果他是一个中断嵌套呢?比如说,另外一个中断把这个中断打断了,那这个时候,首先ISRCounter加1,加1以后进入下一个中断,它又进入OS-IntEnter(),在这个函数中,我们再让这个变量ISRCounter加1,那这个时候,它就变成2了。我们可以看到变量ISRCounte为0,表明没有中断,变量ISRCounte为1,表明中断嵌套层数是1,变量ISRCounte为2,表明中断嵌套层数是2,所以说,我们这个操作系统就是根据这个全局变量来判断当前是不是处于中断嵌套中,如果处于中断嵌套中,就优先执行中断。
进入中断函数:OS-IntEnter();
退出中断函数:OS-IntExit();
在一个操作系统中,我们的中断时间是没办法估量的,但是,我们中断要遵循一个原则:
注意,中断时间越短越好。
为什么呢?因为如果中断的时间比较长,那对我们任务的响应就有问题了,因为中断是可以打断任务的,假设这个任务10毫秒执行一次,但是这个中断已经占用了20毫秒,那很显然,这个任务被打断以后,它20毫秒就不再执行了,就失去了它本身的实时性。所以说这个中断时间过长,会影响我们任务的实时性,但是,中断时间越短越好并不代表不使用中断就最好。