微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 关于RTX51 TINY的分析与探讨

关于RTX51 TINY的分析与探讨

时间:05-30 来源:单片机与嵌入式系统应用 点击:
1 概述

  RTX51 TINY是一种应用于MCS5l系列单片机的小型多任务实时操作系统。它完全集成在Keil C5l编译器中,具有运行速度快、对硬件要求不高、使用方便灵活等优点, 因此越来越广泛地应用到单片机的软件开发中。它可以在单个CPU上管理几个作业(任务),同时可以在没有扩展外部存储器的单片机系统上运行。

  RTX51 TINY允许同时"准并行"地执行多个任务:各个任务并非持续运行,而是在预先设定的时间片(time slice)内执行。CPU执行时间被划分为若干时间片,RTX51 TINY为每个任务分配一个时间片,在一个时间片内允许执行某个任务,然后RTX51 TINY切换到另一个就绪的任务并允许它在其规定的时间片内执行。由于各个时间片非常短,通常只有几ms,因此各个任务看起来似乎就是被同时执行了。

  RTX51 TINY利用单片机内部定时器0的中断功能实现定时,用周期性定时中断驱动RTX51 TINY的时钟。它最多可以定义16个任务,所有的任务可以同时被激活,允许循环任务切换,仅支持非抢占式的任务切换,操作系统为每一个任务分配一个独立的堆栈区,在任务切换的同时改变堆栈的指针,并保存和恢复寄存器的值。RTX51 TINY没有专门的时间服务函数和任务挂起函数,而是通过os_wait()中的参数设定实现的。使用RTX51 TINY时用户程序中不需要包含main()函数,它会自动地从任务0开始运行。如果用户程序中包含有main()函数,则需要利用os_create_task函数来启动RTX51实时操作系统。

2 任务切换

2.1 RTX51 TINY任务状态

  RTX51 TINY的用户任务具有以下几个状态:

  ① 运行(RUNNING)--任务正处于运行中。同一时刻只有一个任务可以处于"RUNNING"状态。
  ② 就绪(READY)--等待运行的任务处于"READY"状态。在当前运行的任务退出运行状态后,就绪队列中的任务根据调度策略被调度执行,进入到运行状态。
  ③ 阻塞(BLOCKED)--等待一个事件的任务处于"BLOCKED"状态。如果等待的事件发生,则此任务进入"READY"状态,等待被调度。
  ④ 休眠(SLEEPING)--被声明过但没有开始运行的任务处于休眠状态。运行过但已经被删除的任务也处在休眠状态中。
  ⑤ 超时(TIMEOUT)--任务由于时间片用完而处于"TIMEOUT"状态,并等待再次运行。该状态与"READY"状态相似,但由于是内部操作过程使一个循环任务被切换,因而单独算作一个状态。

  处于"READY/TIMEOUT"、"RUNNING"和"BLOCKED"状态的任务被认为是激活的状态,三者之间可以进行切换。"SLEEPING"状态的任务是非激活的,不能被执行或认为已经终止。

2.2 RTX51 TINY任务切换

  任务切换是RTX51 TINY提供的基本服务。RTX51 TINY是基于时间片调度算法的操作系统,它支持的是非抢占式的任务切换。所以在一个任务被执行时不能对其进行中断,除非该任务主动放弃CPU的资源,中断才可以打断当前的任务,中断完成后把CPU的控制权再交还该被中断的任务。任务切换有两种情况,一种是当前任务主动让出CPU资源;另一种情况是在当前任务的时间片已经用完的情况下,进行任务切换。CPU执行时间被分成若干个时间片,RTX51 TINY为每个任务分配一个时间片。时间片是通过对变量TIMESHARING的设置来确定的,即用"TIMESHARING EQU 5;"设置多少个系统时钟周期为一个时间片。系统默认5个系统时钟为一个时间片,如果晶振频率为11.059 2 MHz,则时间片为10.850 7×5=54.253 5 ms。

  RTX51 TINY的任务切换共有TASKSWITCHING 和SWITCHINGNOW两个入口,前者供定时器T0的中断服务程序调用,后者供系统函数os_delete和os_wait调用。相应地也有两个不同的出口,分别是恢复保护现场和清除状态标志位。系统首先将当前任务置为"TIMEOUT"状态,等待下一次时间片循环,然后找到下一个处于"READY"状态的任务,通过堆栈管理,将自由堆栈空间分配给该任务,使其成为当前任务。清除使该任务进入"READY"或"TIMEOUT"状态的相关位后,执行该任务。任务切换的流程如图1所示。


图1 任务切换流程

3 共享资源实现[1]

  RTX51 TINY由于是一个多任务的操作系统,那么就不免会有几个任务使用同一个资源,这些资源可能是一个变量,也可能是输入/输出设备。这就要求一个任务在使用共享资源时必须独占该资源,否则可能会造成数据被破坏。

  在RTX51 TINY中实现共享资源独占的方法比较多。比如,可以通过TIMESHARING这个变量来禁止时间片轮转,使其值为0,就可以实现禁止任务切换,从而当前任务就可以独占共享资源。还可以关闭中断来实现,使EA=0,定时器T0的中断被关闭,不能再为时间片轮转提供基准,从而禁止了任务切换。但这两种方法都带有一定的局限性,前一种方法只能适用于实时性要求不高的场合,后一种方法由于T0中断关闭时间不能太长,只能适用于一些简单变量操作的场合。基于以上情况,下面通过另一种方法来实现共享资源的使用。

  在RTX51 full中可以利用信号量很好地实现对共享资源的操作,也可以把这种思想应用到RTX51 TINY中;而在RTX51 TINY中不支持信号量,这就要求用户自己定义信号量及其操作过程。以下是部分代码:

  struct signal {//定义信号量结构体
    uchar count;//该信号量的当前计数值
    uint list_tasks;//等待该信号量任务表
  } signal_list[3];
  /*初始化信号量 */
  void init_signal(uchar task_id,uchar count) {
    signal_list[task_id].count=count;
    signal_list[task_id].list_tasks=0;
  }
  /*等待信号量 */
  char wait_signal(uchar task_id) {
    if(signal_list[task_id].count>0) {
      signal_list[task_id].count;//获取信号量
      return(-1);
    }
    signal_list[task_id].list_tasks|=(1os_running_task_id());//标记为等待状态
    return(0);
  }
  void wait_sem(uchar task_id) {
    if(wait_signal(task_id==0)
      while(os_wait(K_TMO,255,0)!=RDY_EVENT);//等待,直到该任务就绪
  }
  /*释放信号量 */
  char release_signal(uchar task_id) {
    uchar i:
    uint temp=1;
    if((signal_list[task_id].count>0)||( signal_list[task_id].list_tasks==0)) {
      signal_list[task_id].count++; //释放信号量
      return(-1);
    }
    for(i=0;i<16;i++) {
      if((signal_list[task_id].list_tasks&(temp))!=0){//查找任务表
        signal_list[task_id].list_tasks&= ~(1<<i);return(i); //返回等待信号量的任务号
      }
      temp<<=1:
    }
  }
  void release_sem(uchar task_id) {
    char task_temp;
    task_temp=release_signal(task_id);
    if(task_temp!=-1) {
      os_set_ready(task_temp); //任务task_id进入就绪状态
      os_switch_task();
    }
  }

  有了以上几个函数的定义和实现,就可以应用等待信号量和释放信号量来完成对共享资源的独占。例如:

  void job()_task_ id {
      ――――用户代码――――
      wait_sem(task_id);//等待任务task_id的信号量
      ――――对共享资源使用代码――――
      release_sem(task_id);//释放任务task_id的信号量
      ――――用户代码――――
  }

  应用信号量来实现共享资源的使用,不用禁止时间片轮转和关闭T0中断,可以有效地实现对共享资源的独占;但增加了代码,等待和释放信号量花费了一定的时间,在具体应用中要视情况而定。

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top