与每种类型的I/O设备关联的进程在内存底部附近都有一个地址,称为中断向量。它包括中断服务程序的入口地址。当中央处理器正在处理内部数据时,外部发生紧急情况,要求CPU暂停当前工作,转而处理紧急情况。处理完成后,返回原来中断的地址,继续原来的工作。这个过程称为中断。中断处理:(1)保护被中断进程的现场。为使中断处理完成后进程准确返回中断点,系统必须保存当前处理器程序状态字PSW和程序计数器PC的值。(2)分析中断原因,转而执行相应的中断处理程序。当多个中断请求同时发生时,处理优先级最高的中断源发出的中断请求。(3)恢复被中断进程的场景,CPU继续执行原来被中断的进程。三、注意事项1、中断函数代码尽量简洁。一般不宜在中断函数中编写大量复杂冗长的代码;尽量避免在中断函数中调用其他自定义函数;2.尽量避免在中断中调用数学函数。由于一些数学函数涉及到很多相关的库函数调用和中间变量,可能会出现交叉调用。当必须使用数学函数时,考虑将复杂的数学函数运算分配给主程序,中断函数通过全局变量引用其结果;3、宏的定义和调用。在中断函数中调用宏可以减少函数调用中压栈和出栈的开销。九小注意事项1.中断函数不能传参。2、中断函数没有返回值。3.中断函数在任何情况下都不能直接调用。4.中断函数使用浮点运算来保存浮点寄存器的状态。5、如果中断函数中调用了其他函数,被调用函数使用的寄存器必须与中断函数使用的寄存器相同,并且被调用函数最好设置为可重入的。6、(可忽略)C51编译器在编译中断函数时会自动在程序的开头和结尾添加相应的内容,如下:ACC、B、DPH、DPL和PSW在程序开头压入堆栈程序,最后流行音乐。如果中断函数不加usingn修饰符,R0~R1必须在开始时入栈,结束时出栈。如果中断函数加上usingn修饰符,PSW入栈后必须修改PSW中的工作寄存器组选择位。C51编译器从绝对地址8m3生成中断向量,其中m为中断号,即中断后的编号。该向量包含到中断函数入口地址的绝对跳转。7、中断函数最好写在文件末尾,禁止使用extern存储类型描述。防止其他程序调用。8、设计中断时要注意哪些函数应该放在中断程序中,哪些函数应该放在主程序中。一般来说,中断服务程序应该做最少的工作,这样做有很多好处。首先,系统对中断的响应范围更广。有些系统如果丢失中断或者对中断的响应太慢,将会造成非常严重的后果。这时候,有足够的时间等待中断就显得很重要了。其次,可以使中断服务程序的结构简单,不易出错。你在中断例程中放入的东西越多,它们就越容易发生冲突。简化中断服务程序意味着软件中的代码段会更多,但这些都可以放在主程序中。9、中断服务程序的设计对系统的成败起着至关重要的作用。每个中断之间的关系和每个中断的执行时间要仔细考虑,特别要注意那些对相同数据进行操作的中断。它是嵌入式系统的重要组成部分,这导致许多编译器开发人员提供扩展以允许标准C支持中断。表示创建了新关键字__interrupt的事实。下面的代码使用了__interrupt关键字来定义一个中断服务子程序(ISR),请评论这段代码。__interruptdoublecompute_area(doubleradius){doublearea=PI*radius*radius;printf("\nArea=%f",area);returnarea;}这个函数错误太多:1)ISR不能返回值。如果您不了解这一点,那么您将不会被录用。2)ISR不能传递参数。如果你没有看到这个,你被录用的机会和第一项一样。3)浮点数在许多处理器/编译器中通常是不可重入的。一些处理器/编译器需要将寄存器压入堆栈的前端,而一些处理器/编译器不允许在ISR中进行浮点运算。此外,ISR应该简短高效,在ISR中进行浮点运算是不明智的。4)与第三点相符,printf()经常出现重入和性能问题。如果你输了第三点和第四点,我就不会给你太大的麻烦了。不用说,如果你能拿到最后两点,你的就业前景会越来越好。可重入性的解释:printf()经常有可重入性来说明一个不可重入函数在返回前不能被再次调用。比如printf、malloc、free等都是不可重入的函数。因为中断随时都有可能发生,比如在执行printf的过程中,不能在中断处理程序中调用printf,否则会重新进入printf。函数不可重入主要是因为函数中引用了全局变量。例如printf会引用全局变量stdout,malloc,free会引用全局内存分配表。如果发生中断,运行到printf时,假设发生中断嵌套,此时stdout资源被占用,所以第二次中断printf等待第一个中断的stdout资源释放,第一个中断等待第一个中断。两个中断返回,导致死锁。不可重入函数是指在调用函数之前再次调用该函数可能会产生错误。可重入函数没有这个问题。不可重入函数在实现时通常会使用全局资源。在多线程环境下,如果数据保护和互斥处理不好,就会出现错误。常见的不可重入函数有:printf--------引用全局变量stdoutmalloc--------全局内存分配表free--------全局内存分配表通常在unix中都有具有带有_r后缀的同名可重入函数版本。如果不是,不妨在可预见的错误发生的地方尝试加保护锁同步机制等。下面引用别人的解释:这个主要用在多任务环境下。可重入函数只是一个可以被中断的函数。也就是说,你可以在这个函数执行过程中随时打断它的运行,在OS的调度下执行另一段代码,不会出错。不可重入函数使用了一些系统资源,比如全局变量区、中断向量表等,所以如果被中断,可能会出现问题,所以这类函数不能在多任务环境下运行。使不可重入函数可重入的唯一方法是使用可重入规则重写它。其实很简单,只要遵循几个容易理解的规则,那么写出的函数就是可重入的:第一,不要使用全局变量。因为其他代码很可能会覆盖这些变量值。其次,在和硬件交互的时候,记得执行disinterrupt()这样的操作,就是关闭硬件中断。记得打开中断完成交互。在某些系列中,这称为“进入/退出内核”或由OS_ENTER_KERNAL/OS_EXIT_KERNAL描述。第三,您不能调用任何不可重入函数。第四,谨慎使用堆栈。在使用它之前最好先OS_ENTER_KERNAL。还有一些规则,很容易理解。总之,永远记住一句话:确保中断是安全的!通俗地说:因为随时都可能发生中断,所以断点的位置也是不可预测的。因此,必须保证每个函数都具有不受中断、压栈、转向ISR、出栈后继续执行的稳定性。也就是说,它具有不受中断影响的能力。既然有这个要求,你提供和编写的每个函数都不能使用公共资源或变量,因为在使用该函数时,ISR(中断服务程序)也可以修改或获取这个资源。因此,有可能中断返回后,这部分公共资源已经面目全非了。大多数满足以下条件的函数都是不可重入的:(1)函数体中使用了静态数据结构;(2)在函数体中调用了malloc()或free()函数;(3)标准I/O功能。下面举例说明。可重入函数voidstrcpy(char*lpszDest,char*lpszSrc){while(*lpszDest++=*lpszSrc++);*dest=0;}不可重入函数1charcTemp;//全局变量voidSwapChar1(char*lpcX,char*lpcY){cTemp=*lpcX;*lpcX=*lpcY;lpcY=cTemp;//访问全局变量,多线程共享内存可能会出现问题}不可重入函数2voidSwapChar2(char*lpcX,char*lpcY){staticcharcTemp;//staticlocalvariablescTemp=*lpcX;*lpcX=*lpcY;lpcY=cTemp;//使用静态局部变量可能会导致多线程共享内存的问题}可重入函数怎么写?不要在函数体中访问那些全局变量,不要使用静态局部变量,坚持只使用局部变量,写出来的函数就会可重入。如果必须访问全局变量,请记住使用互斥信号量保护全局变量。
