×
嵌入式 > 技术百科 > 详情

中断函数和中断处理函数

发布时间:2020-06-05 发布时间:
|

(1)当你在做一个计算机(嵌入式)系统时,在为系统做初始化时往往会有设置中断向量的操作。

当你设置好某个特定的外部事件(比如定时器超时)的中断向量后,当你允许(使能)了该设备(定时器),那么等到特定时刻(定时器超时),外设(定时器)会向你CPU核心发送外部中断请求,如果此时没有对它进行任何屏蔽的话,并且也没有比它优先级更高的中断事件处于未决状态的话,那么此时该事件的中断发生。
  

为了能够对该事件处理,必须要有一个处理该中断事件的函数入口地址,称该地址为中断向量。
  

因此中断向量位置一般是由CPU(硬件)来决定的,而里面对于特定中断事件的处理可以由开发人员进行自由地软件编程。

但是,在处理完该中断事件后,也就是要返回该中断向量函数,必须要使用特殊的中断返回指令(在X86系统中为IRET;在Blackfin指令集中为rti)。

问题1:为什么说中断向量函数不需要有返回值?

回答: 因为中断事件是异步发生的。当系统在接受一个中断事件,对它进行处理,完了之后,如果有返回值,那么由谁来处理这个返回值呢?
     

况且一个中断可能会发生在不同的线程中,或者在上下文切换之际发生(这种情况可能会比较少,有些系统在做上下文切换时,往往会屏蔽所有可屏蔽中断。但是上下文切换也往往存在临界去【Critical Region】和非临界区)。因此对于中断向量函数的返回值是无法进行处理的。而如果说要以调用普通函数的方式为它传递参数就更不可能了。你只能为中断向量函数提供某种区域(其所能访问的)的相对全局变量,对该变量设定值,然后在该中断向量函数中进行处理;或者是通过写某个相对全局变量的值,以此作为返回。

比如:


  • C/C++ code

  • volatile int argument = 0, retValue = 0; // the key word "volatile" here is necessary // The following pragma is pseudo, that only describes the effect of the interrupt vector function#pragmainterrupt_vector(TIMER) // @0x00001000 the address of the vector for timer eventvoidtimer_vector_handler(void) { save_context(); // Save the context(almost all the general registers)retValue = toggle_led(LED1, &argument); // According to argument, If argument is 0, turn it off; Otherwise, turn it on. // Then, the value of argument is toggled. // retValue is a return vbalue that indicates whether the operation is successful or not. reset_timer(); // clear the timer interrupt status and reset the timer. restore_context(); // resotre the context saved before //iret(); // Because the function is predeclared as #pragma interrupt_vector, // the compiler may automatically generate "iret" instruction at the end of the fucntion}



问题2:那么一些带有参数或返回值的中断处理函数又是什么呢?

回答: 这些中断处理函数一般是基于操作系统下的用户自定义处理函数。比如说,在Windows系统下,应用程序编写者可以通过使用一个定时器来处理很多事情。

但是应用程序用户别指望直接使用内核提供的中断向量函数对定时器进行操作,相反,操作系统对于定时器有个定时器事件的管理。

比如说定时器1可以观察64个状态值,一旦某个值处于超时状态,就会调用其相应的由应用程序编写者先前所注册的中断处理函数进行回调。而这些用户自定义函数可以有返回值或带有参数。

比如,用于进行Windows桌面程序编程的MFC库中的SetTimer函数:


  • C/C++ code

  • UINT SetTimer( UINT nIDEvent, UINT nElapse, void ( CALLBACK* lpfnTimer )(HWND, UINT, UINT, DWORD)= NULL ) throw();


 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
Keil5(MDK5)在调试(debug)过程中遇到的问题