立即注册 找回密码

微雪课堂

搜索
微雪课堂 操作系统 μC/OS-II卧槽宝典 查看内容

《μC/OS-II卧槽宝典(上)》【连载 第三章 风水轮流转-2】

2016-9-26 15:18| 发布者: waveshare-admin| 查看: 3005| 评论: 0

摘要: 前面我们大概讨论了任务切换,还没涉及调度等基础且核心的内容。 本节接着就针对μC/OS-II简单说明下这些内容。
· μC/OS-II怎样实现多任务
前面我们大概讨论了任务切换,还没涉及调度等基础且核心的内容。
本节接着就针对μC/OS-II简单说明下这些内容。
调度思想
每个操作系统内核有自身的任务调度思想。多数实时内核基于优先级调度。
基于优先级调度的意思是:内核总是让处于就绪态的、优先级最高的任务先运行。
基于优先级调度的内核还分为两种:不可剥夺型、可剥夺型。μC/OS-II的内核为可剥夺型。
多数实时内核都是可剥夺型:优先级最高的任务一旦就绪,总能得到CPU使用权,而原来运行的任务就挂了。
顺便提下,某些OS支持时间片轮转(如μC/OS-III),某些则不支持(如μC/OS-II)。
调度器
查找最高优先级就绪任务,并确定是否让它运行的工作由调度器(Scheduler)完成。
任务级的调度由函数OSSched()完成。中断级的调度由另一个函数OSIntExt()完成,这些函数将在以后说明。
『任务的状态』
μC/OS-II的任务有五种状态:
·休眠态:任务驻留在内存中,但并不被操作系统调度。
·就绪态:任务已经准备好,可以运行,但是由于比它优先级更高的任务在运行,所以,它暂时还不能运行。
·运行态:任务掌握了CPU的使用权,正在运行。
·挂起态:任务在等待某一事件(共享资源、信号)的发生。
·被中断态:任务被中断,暂时得不到运行。
任务的组成
μC/OS-II的任务由以下三部分组成:
·任务控制块
  前文提到:
·将当前任务的SP保存到全局变量中,μC/OS做的是将SP保存到“当前运行任务控制块”中。
·将当前任务更新为即将运行任务,μC/OS做的是将“当前任务控制块指针”指向“即将运行任务控制块”。
实际上,任务控制块还有很多用途,更多相关说明请参阅后面章节。
·任务堆栈
这个前面章节已有相关说明,简单来说,就是各个任务有自己的堆栈。
·任务程序代码
  这个显而易见,每个任务当然有自己的程序代码。

· 前后台系统与实时系统对比
  
项目
  
前后台系统
可剥夺型实时系统
任务响应时间
由具体情况决定(程序员编程时需把握)
寻找最高优先级任务时间 + 任务切换时间
占用ROM
应用程序代码
应用程序代码 + 内核
占用RAM
应用程序全局变量(固定) + 局部变量(动态)
应用程序全局变量 + 内核RAM + 任务栈 + MAX(ISR栈)

· 临界区
由于实现多任务,需要保护临界区,所以,“临界区”也就暂寄放在这(不排除以后调到其它章)。
【临界资源与临界区】
临界资源是一次仅允许一个进程使用的共享资源。全局变量是一种临界资源。
不论是硬件临界资源,还是软件临界资源,多个进程必须互斥地对它进行访问。
每个进程中访问临界资源的那段代码称为临界区(CriticalSection)。
每次只准许一个进程进入临界区,进入后不允许其他进程进入。
不论是硬件临界资源,还是软件临界资源,多个进程必须互斥地对它进行访问。
【保护临界区的实现】
关中断可使得系统能够避免同时有其它任务或中断服务进入临界区。
在μC/OS-II中,定义了两个宏,以避免不同C编译器厂商选择不同的方法来处理开关中断。
这两个宏是:
·OS_ENTER_CRITICAL():进入临界区。
·OS_EXIT_CRITICAL():离开临界区。
它们总是成双成对,不离不弃,将临界区“夹住”。
【进出临界区的实现方式】
在μC/OS-II中,有三种方式可以实现进出临界区,选择哪种方法由OS_CRITICAL_METHOD决定。
OS_CRITICAL_METHOD = 1
·OS_ENTER_CRITICAL():用CPU指令关中断。
·OS_EXIT_CRITICAL():用CPU指令开中断。
这种方式虽然最简单,但有如下缺点:离开临界区后,中断总是被打开。而如果,进入临界区前,中断是被关着的,显然不应被打开。在Jean.J.Labrosse著的μC/OS-II(第2版)中,提到:“对一些CPU或编译器,使用这种方式却是唯一选择。”
OS_CRITICAL_METHOD = 2
·OS_ENTER_CRITICAL():在堆栈中保存中断的开关状态,然后再关中断,示例代码如下:
#define OS_ENTER_CRITICAL() asm("PUSH PSW")asm("DI")
·OS_EXIT_CRITICAL():从堆栈中弹出中断的开关状态,示例代码如下:
#define OS_EXIT_CRITICAL() asm("POP PSW")
这种方式能够得到原来中断的开关状态(中断的开关状态记录在PSW中),但却很可能由于编译器对插入的行汇编支持不好,导致以上方法不可行,或者说导致严重错误。因为,PUSH的出现导致了堆栈指针发生了改变,这样,在临界区内存取若存放在栈中的局部变量,就不再是局部变量原来的地址了。
OS_CRITICAL_METHOD = 3
·OS_ENTER_CRITICAL()将CPU的状态寄存器值保存到局部变量cpu_sr,在笔者的工程中,代码如下:
  #define OS_ENTER_CRITICAL()  {cpu_sr =OS_CPU_SR_Save();}
OS_CPU_SR_Save
      MRS    R0, PRIMASK     ;保存全局中断标志
      CPSID  I                ;关中断
      BX      LR
·OS_EXIT_CRITICAL():将cpu_sr装回CPU的状态寄存器,在笔者的工程中,代码如下:
  #define OS_EXIT_CRITICAL()  {OS_CPU_SR_Restore(cpu_sr);}
OS_CPU_SR_Restore
      MSR    PRIMASK, R0      ;恢复全局中断标志
      BX      LR
这种方式能够得到原来中断的开关状态,条件是:CPU拥有状态寄存器,且状态寄存器的某一位可以被用来标识某处理器设置中断的办法。大部分ARM都采用本方式保护临界区。

-------------------------------------------------------------------------------------------------------------------------------------------
① 也就是说,无法使用方式2及方式3,也就是无法读写PSW(可能根本就没有PSW)。笔者认为,如果使用方式1,要解决前文提到的缺点,则只能是:
开关中断时(进出临界区除外),将中断记录到某个全局变量中,相应的,恢复中断,则是读取相应的全局变量。
② 由于函数返回值存在R0中,所以将PRIMASK放到R0,之后,即可通过代码“cpu_sr =OS_CPU_SR_Save();”将cpu状态寄存器存到cpu_sr中。
-------------------------------------------------------------------------------------------------------------------------------------------

【保护临界区的注意事项】
使用OS_ENTER_CRITICAL()、OS_EXIT_CRITICAL()的方式来保护临界区要注意:如果在调用一些如OSTimeDel()之类的功能函数之前关中断,应用程序将会崩溃。这个问题是这样引起的:任务被挂起一段时间,直到挂起时间到,但由于中断关掉了,时钟节拍中断一直得不到服务。显然,所有的挂起(PEND)类调用都存在这类问题。
读者可以记得一条普适规则:调用功能函数时,中断应当总是开着的。

313

顶一下

刚表态过的朋友 (313 人)

相关阅读

最新评论

μCOS-II

微雪官网|产品资料|手机版|小黑屋|微雪课堂. ( 粤ICP备05067009号 )

GMT+8, 2024-12-22 16:37 , Processed in 0.018335 second(s), 21 queries .

返回顶部