原创 实时操作系统应用杂谈(二)

2009-12-5 13:55 1929 8 8 分类: MCU/ 嵌入式

    想要在自己设计的嵌入式系统中使用操作系统,先要配置或者移植操作系统。相关的文集比较多,在这里我就不说了,我还是想多聊些应用方面的东西。

    关于任务的建立和运行。
    任务的建立是指写一个任务程序。
    任务的运行是指让系统执行一个任务。
RTX51Tiny例:
void mytask2(void) _task_ 1  //任务编号为1的任务
{
  ...;
  while(1){
      ...;
  }
}
 
void mytask1(void) _task_ 0  //任务编号为0的任务,首先执行
{
  ...;//必要的初始化
  os_create_task(1);    //建立编号为1的任务,即允许编号为1的任务执行,但不是立即执行
  while(1){
    ...;    //任务过程。
    ...;    //在许多操作系统的例程中,都不约而同地把第一个任务运行后删除。我觉得没必要。
    ...;    //毕竟开一个任务需要占用不少资源,没必要浪费。
  }
}
 
    RTX51任务程序不带输入参数。但其他大多数的任务程序都支持带参数,带参数的例子后面还会提到。
    任务程序的后缀,只有在操作系统与编译系统捆绑在一起的情况下才有。keil下的RTX51和RL-RTX都是如此。
    RTX51Tiny任务有后缀“_task_ TASKID”,需要指定任务编号。由于RTX51没有任务优先级,任务依靠时间片来调度,因此RTX51引入任务编号的概念,在这在其他操作系统中是不存在的。在RL-RTX中,后缀为“__task”。 在RTX51中,任务编号为0的任务是必须的,由于不需要main()程序,系统总是从任务编号为0任务程序开始运行。
    大多数操作系统环境下,main()程序是必要的。在main()程序中,可以进行某些与操作系统无关的配置工作。更重要的是,操作系统的启动需要在main()程序中(除了少数系统如TiDSPBIOS)。
    RTX51其他任务的执行需要在0号任务中使用os_create_task(TASKID)函数。“TASKID”就是需要运行的任务的编号。在大多数操作系统中,都是以类似的CREATE_TASK函数来启动其他需要运行的任务。但也有少数操作系统支持“静态”创建并运行任务的,如TiDSPBIOS,可以在操作系统中直接设置需要运行任务,系统运行时,操作系统就会按已配置的顺序和优先级启动各个任务的运行。
    绝大多数操作系统都支持任务程序带输入参数。比较普遍的意义,就是可以在任务中减少使用全局变量,从而优化任务程序、方便任务的移植。还有比较实用的方面就是以一个任务程序建立多个应用。这就好比写一个类,在运行时,创建多个应用。下面举个简单的例子。
    MCU的P0口,其8个输出各控制1个LED。第1个LED每5秒闪一下,第2个LED每2秒闪一下,等等。每次点亮时间100ms。
  示例程序如下:
//定义通道及延时的数据结构 
typedef struct channel{
  int ch;    //通道
  int dly;  //延时
}ChannelObj;
ChannelObj ch[8]={  //通道定义,全局变量
  0,5,  //通道0,延时5秒
  1,2,  //通道1,延时2秒
  2,3,  //...
  3,7,
  4,6,
  5,4,
  6,8,
  7,1,
};


//定义任务优先级
#define TASK_MAIN_PRIO  1
#define TASK_APP_PRIO  2
 
int main(void){
  //硬件初始化(已简略)
  //P0.0-7端口初始化
  SCS = 1;        //启用高速IO口
  PINSEL0 &= 0xFFFF0000;  //选择IO口
  FIO0DIR0 = 0xFF;    //选择输出
  FIO0CLR0 = 0xFF;    //全部输出低电平
  //与操作系统无关的初始化可以放在main()中。
  //... 
  os_sys_init_prio(task_main,TASK_MAIN_PRIO);//启动task_main任务
  while(1);
}


void task_main(void * pdata) __task {
  char i;
  OS_TID tskid[8];
  for (i=0;i<8;i++){
    //建立8个通道任务,传入相应参数。
    tskid = os_tsk_create_ex(task_app,TASK_APP_PRIO,&ch);
  }
  while(1){
    ...;
    ...;//可以在此或其他任务中变更通道的延时参数ch.dly。
  }
}
 
void task_app(void * para) __task {
  ChannelObj * app_ch;
  app_ch = (ChannelObj *)para;//导入通道参数
  while(1){
    int s;
    ch_mask;
    ch_mask = 0x01 << (app_ch->ch);   
    FIO0SET0 = ch_mask;  //点亮该通道LED
    os_dly_wait(10);     //点亮延时100ms
    FIO0CLR0 = ch_mask;  //熄灭该通道LED
    for (s=0;s<app_ch->dly;s++)os_dly_wait(100);  //熄灭延时1s*延时参数
  }


    在该示例中,由于每个通道的运行模式是一样的,唯一不同的是延时参数不一致,因此可以只为通道的运行流程写一个任务程序(task_app),运行时由task_main任务建立多个task_app任务,即8个通道由8个任务实例独立运行。这充分地突出了多任务操作系统的优势。
    上述示例表明了多任务的一种应用方法。其他的应用,诸如多线程的网络服务应用,分布式信号采集等等,都可以应用类似的方法。
 
 

PARTNER CONTENT

文章评论0条评论)

登录后参与讨论
EE直播间
更多
我要评论
0
8
关闭 站长推荐上一条 /3 下一条