中断函数和中断处理函数

(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 #pragma interrupt_vector(TIMER)  //  @0x00001000 the address of the vector for timer event void timer_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 ();
 
 


上面第三个参数就是指向用户定时中断处理函数的指针,并且带有4个参数。

 

from:http://topic.csdn.net/u/20080704/10/9f105765-5cd1-4def-badc-3d067f0704e3.html

  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 在 C51 中使用定时器中断实现延时可以通过以下步骤实现: 1. 配置定时器,设置中断时间。具体方法可以参考 C51 的开发文档或相关教程。 2. 在中断服务程序中设置一个标志位,表示时间已经到达。 3. 在需要延时的地方,循环检测标志位是否被置位,如果没有则继续等待,直到标志位被置位。 4. 清除标志位,重新启动定时器,继续执行下一次延时。 下面是一个示例代码: ```c #include <reg51.h> #define TIME_MS 50 // 延时时间,单位为毫秒 bit flag; // 中断标志位 void init_timer() // 定时器初始化函数 { TMOD |= 0x01; // 设置定时器0为模式1 TH0 = (65536 - 50000) / 256; // 设置定时器初值 TL0 = (65536 - 50000) % 256; ET0 = 1; // 开启定时器中断 EA = 1; // 开启总中断 TR0 = 1; // 启动定时器 } void timer0_isr() interrupt 1 // 定时器中断服务程序 { flag = 1; // 设置标志位 } void delay_ms(unsigned int ms) // 延时函数 { flag = 0; // 清除标志位 while (ms--) { while (!flag); // 等待标志位置位 flag = 0; // 清除标志位 } } void main() { init_timer(); // 初始化定时器 while (1) { P1 = 0x55; // 亮灯 delay_ms(TIME_MS); // 延时 P1 = 0xAA; // 灭灯 delay_ms(TIME_MS); // 延时 } } ``` 上述代码中,初始化定时器函数 `init_timer()` 中设置了定时器0为模式1,即16位自动重装载计数器, TH0 和 TL0 初值为 50000 的补码,实现了 50ms 的定时中断。在中断服务程序 `timer0_isr()` 中设置了标志位 `flag`,表示时间已到。在延时函数 `delay_ms()` 中,通过循环检测标志位来实现延时,具体实现方式是等待标志位被置位,然后清除标志位,继续等待下一次延时。在主函数中,通过不断亮灭 LED 灯来测试延时函数的正确性。 ### 回答2: C51定时器中断延时函数用于延时一段时间,并且在延时期间可以执行其他的代码。下面是一个用C语言实现的简单的C51定时器中断延时函数的例子: ``` #include<reg52.h> unsigned int count = 0; // 定义计数变量 void Timer0_Init() { TMOD |= 0x01; // 将T0工作在模式1:16位定时器 TH0 = 0xFC; // 设置定时器的初值,延时1ms TL0 = 0x18; ET0 = 1; // 使能定时器0中断 EA = 1; // 全局使能中断 TR0 = 1; // 启动定时器 } void Timer0_ISR() interrupt 1 // 定时器0中断服务函数 { TH0 = 0xFC; // 重新加载定时器的初值 TL0 = 0x18; count++; // 每次中断count加1 } void Delay_Ms(unsigned int ms) // 定时器中断延时函数 { count = 0; // 将计数变量清零 while(count < ms); // 等待计数变量达到指定的延时时间 } void main() { Timer0_Init(); // 初始化定时器 while(1) { P1 = 0xFF; // 点亮所有LED灯 Delay_Ms(1000); // 延时1000ms P1 = 0x00; // 关闭所有LED灯 Delay_Ms(1000); // 延时1000ms } } ``` 以上代码的实现使用C51的定时器0进行中断延时,首先在Timer0_Init函数中设置了定时器0的模式和初值,然后在Timer0_ISR中断服务函数中,重新加载定时器的初值,并将计数变量count加1。最后,在Delay_Ms函数中,通过判断计数变量是否达到指定的延时时间来实现延时功能。 ### 回答3: C51定时器中断延时函数是一种通过使用C51单片机的定时器中断功能来实现延时功能的方法。 在C51单片机中,可以使用定时器中断功能来精确定时,从而实现延时功能。我们可以通过设置定时器的计数值和预分频系数,来控制定时器溢出的时间间隔。当定时器溢出时,会触发定时器中断,我们可以在中断服务函数中进行相应的延时操作。 以下是一个简单的C51定时器中断延时函数的示例: ```c #include <reg51.h> unsigned char count = 0; // 定义计数器变量 void Timer0_Init() { TMOD = 0x01; // 设定定时器0为工作模式1 TH0 = 0xFC; // 定时器初值设置 TL0 = 0x18; EA = 1; // 允许中断 ET0 = 1; // 启用定时器0中断 TR0 = 1; // 启动定时器0 } void Delay(unsigned int ms) { while(ms--) { count = 0; // 计数器清零 while(count < 20); // 延时约1ms } } void Timer0_ISR() interrupt 1 { TH0 = 0xFC; // 重新装载定时器初值 TL0 = 0x18; count++; // 计数器加1 } void main() { Timer0_Init(); // 初始化定时器0 EA = 1; // 开启总中断 Delay(300); // 延时300ms // 其他操作 } ``` 上述代码中,使用定时器0进行中断延时。在主函数中,首先需要调用`Timer0_Init()`函数来初始化定时器0。然后,调用`Delay()`函数进行延时操作,参数为要延时的毫秒数。最后,进行其他操作。 在中断服务函数`Timer0_ISR()`中,重新装载定时器初值,计数器变量`count`加1。 这样,通过定时器中断的不断触发和计数器的累加,就可以实现精确的延时功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值