当前位置:
文档之家› 第3章 μCOS-II的中断和时钟
第3章 μCOS-II的中断和时钟
cpu_sr = get_processor_psw();
disable_interrupts(); /* 处理临界代码*/ set_processor_psw(cpu_sr);
}
3.2 uC/OS-II的时钟
• 任何操作系统都要提供一个周期性的信号源,以供系统处理诸如 延时、超时等与时间有关的事件,这个周期性的信号源叫做时钟。 • 与大多数计算机系统一样,用硬件定时器产生一个周期为毫秒级 的周期性中断来实现系统时钟。最小的时钟单位就是两次中断之 间间隔的时间,这个最小时钟单位叫做时钟节拍。 • 硬件定时器以时钟节拍为周期定时的产生中断,该中断的中断服 务程序叫做OSTickISR(),中断服务程序通过调用函数 OSTimeTick()来完成系统在每个时钟节拍时需要做的工作。
为记录中断嵌套的层数 , μ C/OS-II内核定义 了一个全局变量 OSIntNesting。
NO
}
OSIntNesting++; } }
NO
任务是被中断的任务?
返回中断服务程序
if(OSIntNesting > 0){
NO 获得任务TCB的指针
OSIntNesting--;
执行中断级任务切换
这个函数在中断嵌套层数 计数器为0、调度器未被锁 定且从任务就绪表中查找 到的最高级就绪任务又不 是被中断的任务的条件下 将要进行任务切换,否则 就返回被中断的任务程序
C/OS节拍率最好选在10→100次/秒。 必须在多任务系统启动OSStart()以后,再开启时钟节拍器。
13
3.2.1 时钟节拍中断服务子程序
程序清单 : 时钟节拍中断服务子程序的示意代码
void OSTickISR(void) { 保存CPU寄存器; 调用OSIntEnter(); if(OSIntNesting == 1) { OSTCBCur -> OSTCBStkPtr = SP; } 调用OSTimeTick(); 清除中断; 开中断; 调用OSIntExit(); 恢复CPU寄存器; 执行中断返回指令; } // 记录中断嵌套层数
11
3.1.6.3 开关中断的实现方法3
•
•OS_CRITICAL_METHOD==3 把当前处理器的状态字保存在局部变量中(如OS_CPU_SR),关中断时保存, 开中断时恢复。这样需要在选择用这种方法进入临界代码的应用程序中定义一个 局部变量cpu_sr。
void Some_uCOS_II_Service(arguments) { OS_CPU_SR …… cpu_sr 方法3的示意性代码 #define OS_ENTER_CRITICAL()
三、 uC/OS-II的中断和时钟
1
第三章:uC/OS-II的中断和时钟
目标: 本章旨在向学员介绍uc/osII实时操作系统 的中断概念及时间管理,通过本章的学习, 学员应该掌握如下知识: uC/OSII的中断管理和中断服务程序的 结构 uC/OSII的系统时钟及实现方法 时间管理服务:延时、取消延时
方法2的示意性代码
#define OS_ENTER_CRITICAL()
asm(“PUSH PSW”) asm(“DI”) #define OS_EXIT_CRITICAL() asm(“POP PSW”)
第2种方法可使CPU 中断允许标志的状态 在临界段前和临界段 后不发生改变。
一些编译器对插入的行汇编代码优化得并不好,上述办法未必可行,尤其是堆栈指针相对寻址模式时。
图3-2 函数OSIntExit()的流程图
} OS_EXIT_CRITICAL();
5
3.1.3 中断服务子程序的流程
中断服务子程序入口 CPU寄存器内容进栈 调用OSIntEnter()通知系统:进入中断服务程序 NO 调用OSIntExit()通知系统:退出中断服务程序 恢复CPU寄存器内容 执行中断返回指令
因为使用C语言不便于对CPU 的寄存器进行处理,所以这段 代码使用汇编语言编写。
// 在任务TCB中保存堆栈指针 // 时钟节拍服务处理
15
3.2.2 时钟节拍服务函数
void OSTimeTick (void) { OS_TCB *ptcb; OSTimeTickHook();
#if OS_TIME_GET_SET_EN > 0 OS_ENTER_CRITICAL(); OSTime++; // 记录节拍数 OS_EXIT_CRITICAL(); #endif if (OSRunning == TRUE) { 不会让处于挂起、延 ptcb = OSTCBList; 时双等待态任务因延 while (ptcb->OSTCBPrio != OS_IDLE_PRIO) { 时时间到而就绪。 OS_ENTER_CRITICAL(); if (ptcb->OSTCBDly != 0) { if (- -ptcb->OSTCBDly == 0) { //任务的延时时间减1 if ((ptcb->OSTCBStat & OS_STAT_SUSPEND) == OS_STAT_RDY) { OSRdyGrp |= ptcb->OSTCBBitY; OSRdyTbl[ptcb->OSTCBY] |= ptcb->OSTCBBitX; } else { ptcb->OSTCBDly = 1; } } } 简单地说,函数OSTimeTick()的任 ptcb = ptcb->OSTCBNext; 务就是在每个时钟节拍了解每个任 OS_EXIT_CRITICAL(); } 务的延时状态,使其中已经到了延 } }
• • •
9
3.1.6.1开关中断的实现方法1
根据微处理器和C编译器的不同,通过在移植文件OS_CPU.H • OS_CRITICAL_METHOD==1 用处理器指令关中断 中配置OS_CRITICAL_METHOD 来选择开/关中断的方法:
• 执行OS_ENTER_CRITICAL(),关中断 • 执行OS_EXIT_CRITICAL(),开中断;
7
3.1.5 临界段
临界段的概念: 在应用程序中经常有一些代码段必须不受任何干扰地连续运行, 这样的代码叫做临界段。 怎样保证临界段的安全? 系统当有异步事件发生时会引发中断请求,CPU何时响应这个 请求?
宏OS_ENTER_CRITICAL()和OS_EXIT_CRITICAL()实现中断的
cpu_sr = get_processer_psw();
disable_interrrupts(); #define OS_EXIT_CRITICAL() set-processer_psw(cpu_sr); 第3种方法的前提条件:用户使用C编译器具 有扩展功能,用户可获得程序状态字的值,这 样就可以把该值保存在C语言函数的局部变量 中,而不必压到堆栈里。 12
开放和关闭(封装了与系统硬件相关的关中断和开中断指令,增 强了可移植性)。
8
3.1.6 开关中断的宏
当处理临界段代码时,需要关中断,处理完毕后,再开中断; 关中断时间是实时内核重要的指标之一; 在实际应用中,关中断的时间很大程度中取决于微处理器的结构和 编译器生成的代码质量; • C/OS-II定义两个宏开关中断: OS_ENTER_CRITICAL(); OS_EXIT_CRITICAL(); 因为这2个宏的定义取决于所使用的微处理器,因此在OS_CPU.H中 可以找到相应的宏定义。 OS_CPU.H是微处理器相关的。
中断嵌套层OSIntNEsting=1?
YES OSTCBCur->OSTCBStkPtr=SP
清中断源的中断申请标志 重新开放中断 运行中断服务代码
并非为每个任务都定义一个充分大的栈空 间,中断嵌套时单独定义一个中断嵌套栈 ,在发生第1次中断时,中断服务程序将栈 空间切换到中断嵌套栈,这样,以后发生的嵌 套中断就一直使用这个栈空间。 异步事件产生中断后,通常用一个任务来完 成对异步事件的处理工作,而在中断服务程 序中只是采用向任务发送消息的方法去激活 这个任务(将该任务置于就绪态,一般该任 务优先级较高从而发生抢占)。
学时:3.0学时 教学方法:讲授ppt+上机练 习+点评+案例分析
2
3.1 uC/OS-II的中断
中断:任务在运行过程中,应内部或外部异步事件的请求中止当 前任务,而去处理异步事件所要求的任务的过程叫做中断。 中断服务程序:应中断请求而运行的程序叫中断服务子程序(ISR)。
中断向量:中断服务子程序的入口地址叫中断向量。
方法1的示意性代码 #define OS_ENTER_CRITICAL() asm(“DI”) #define OS_EXIT_CRITICAL() asm(“EI”)
以上代码所列假定编译器允许直接在C代码行之间插入行汇编语句。
10
3.1.6.2 开关中断的实现方法2
•
• OS_CRITICAL_METHOD==2 实现OS_ENTER_CRITICAL()时,先在堆栈中保存中断的开/关状态,然后再关 中断;实现OS_EXIT_CRITICAL()时,从堆栈中弹出原来中断的开/关状态;
图3-3 中断服务子程序的流程图
6
3.1.4 中断级任务切换
与任务级切换函数OSCtxSW()的原因一样,中断级任务切换函数OSIntCtxSw()通常 是用汇编语言来编写的:
OSIntCtxSw() { OSTCBCur = OSTCBHighRdy; OSPrioCur = OSPrioHighRdy; SP = OSPrioHighRdy->OSTCBStkPtr; IRET; } // 使SP指向待运行任务堆栈 // 中断返回,使PC指向待运行任务 用出栈指令把R1、R2……弹入CPU的通用寄存器; // 任务控制块的切换