您现在的位置: 主页 > 嵌入式操作系统 > UC/OS ii > ucosii解析 uCOS实时操作系统——uCOS事件标志组Flag
本文所属标签:
为本文创立个标签吧:

ucosii解析 uCOS实时操作系统——uCOS事件标志组Flag

来源: 网络用户发布,如有版权联系网管删除 2016-06-06 

uCOS实时操作系统——uCOS事件标志组Flag  

 

  uCOS事件标志组管理OS_Flag.C

  事件标志组是用来干什么的呢?在一个网友的博客上看到一个描述,用一个很形象的例子说明了这个事件组的用途。

  现在要用迅雷下载一部10集的连续剧,10集全部下载完成之后才开始正式看。现在3~10集因为种子原因,先下载完成了。而第1集下载到83%,第2集下载到97%。因为计划是10集全部下完才开始看,而第1集和第2集由于网络和种子等各种原因,迟迟不能下载完成,进而导致计划被悬停,不能进行。已下载的8集也因为前2集没能下完而白白等待,不能观看。这就等同于Flag事件组。

  1~10集,每一集都是一个事件,内定10个事件全部完成之后,才进入下一个事件——“观看”。所以,及早完成自己事件的第3~10集,将主动把自己通过flag事件组函数OSFlagPost()登记到事件组上,它们不关心其它友邻事件是否完成,只专注自己的事件是否完成,自己的事件一旦完成,就登记到事件组上。最后3~10集都把自己登记上去了,只剩下第1集和第2集,一旦某天的某个时刻,第2集下载完成了,第2集也把自己登记到事件组上去,这样整个事件距离完成就剩下一个事件,就是第1集是否下载完成。只要第1集下载完成,内定的“观看”计划就可以开始启动。

  过了2钟,由于网速提高,竟以400K的速度开始下载第1集,很快第1集也载完成了。第1集立即调用OSFlagPost()事件函数将自己登记到事件组上。OSFlagPost()检测到所有事件已经完成,OSFlagPost()将自动进入下一事件——“观看”。

  Flag事件组与Sem、Mbox、Queue的区别之处,事件组不使用事件控制矩阵来管理被阻塞在事件上的task进程,Flag事件组使用pgrp的双向链表来挂起所有task,在OSFlagPost()中遍历这个链表,查找符合当前事件的task,将该task从双向链表中摘下,然后放入就绪控制矩阵中。之所以这样,是因为事件组不像Sem、Mbox、Queue那样具有二值性,即Sem、Mbox、Queue要么有要么没有,Flag事件组还要进一步判断,有的话,是什么程序的有。

  通过以上介绍,对Flag事件的用途有了大致的了解,在详细讲述之前,先上个简单的例子,加深一下对事件组使用的理解。

  简单的OSFLAGPEND()与OSFLAGPOST()函数的应用

显示用,LCD1602和两个LED灯(条件有限啊)

TASK1():建一个OSFlagPend() 若等待事件标志没有发生 该函数挂起该任务若事件标志发生,则LCD显不一个值,LED灯每隔一秒闪一次。

TASK2():OSFlagPost()向任务一发送一个信号量

TASK3():OSFlagPost()向任务一发送一个信号量,具体看代码

static void Task1(void *pdata)
{
    INT8U error;
    INT8U i=0;
    pdata = pdata;
   
    while(1)
    {    
    
         //若等待事件标志没有发生 该函数挂起该任务
        OSFlagPend(
                  Sem_F,             //请求信号量集
                  (OS_FLAGS)3,       //请求第0位和第1位信号
                  OS_FLAG_WAIT_SET_ALL,//且都置为1时为有效 否则任务挂在这里
                  0,                  //无限等待 直到收到为止
                  &error);
        //OSFLAGPEND收到有效信号后 在LCD显示字符串 闪两个LED 可以跟据自己代码而定
        write_com(0x80+10);
        while(table1[i] != '\0')
        {
          write_dat(table1[i]);
          i++;
        }
       
        GPIO_ResetBits(GPIOD, GPIO_Pin_15);
        GPIO_ResetBits(GPIOD, GPIO_Pin_13);
       
        OSTimeDlyHMSM(0,0,1,0);     //任务挂起1秒 否则优先级低的任务就没机会执行了
       
        GPIO_SetBits(GPIOD, GPIO_Pin_15);
        GPIO_SetBits(GPIOD, GPIO_Pin_13);
        OSTimeDlyHMSM(0,0,1,0);     //让两个LED每秒闪一次
    }
}

static void Task2(void *pdata)
{
    INT8U error;
    pdata = pdata;
    while(1)
    {
      OSFlagPost(     //发送信号量集
   Sem_F,
   (OS_FLAGS)2,    //给第1位发信号
   OS_FLAG_SET,    //信号量置1
   &error
   );   
        OSTimeDlyHMSM(0, 0, 1, 0);   //等待1秒
    }
}

static void Task3(void *pdata)
{
    INT8U error;
    pdata = pdata;
    while(1)
    {
     //在执行此函数时 发生任务切换 去执行TASK1 在OSFLAGPOST中发生任务切换
    
      OSFlagPost(     //发送信号量集
   Sem_F,
   (OS_FLAGS)1,    //给第1位发信号
   OS_FLAG_SET,    //信号量置1
   &error
   );   
      OSTimeDlyHMSM(0, 0, 1, 0);   //等待1秒
    }
}

MAIN函数大致如下:

void main(void)
{
    #if (OS_TASK_NAME_SIZE > 14) && (OS_TASK_STAT_EN > 0)
    INT8U err;
    #endif
    //目标板初始化,
    Target_Init();
    lcd_init();
   
    OSInit();
   
    //设置空闲任务名称
    #if OS_TASK_NAME_SIZE > 14
    OSTaskNameSet(OS_TASK_IDLE_PRIO, "uC/OS-II Idle", &err);
    #endif
    //设置统计任务名称
    #if (OS_TASK_NAME_SIZE > 14) && (OS_TASK_STAT_EN > 0)
    OSTaskNameSet(OS_TASK_STAT_PRIO, "uC/OS-II Stat", &err);
    #endif
    

    Sem_F = OSFlagCreate(0,&error);
    //用任务建立任务
    OSTaskCreateExt(APP_TaskStart,                                        //void (*task)(void *pd) 任务首地址
                    (void *)0,                                            //void *pdata           数据指针
                    &APP_TaskStartStk[APP_TASK_START_STK_SIZE - 1],       //OS_STK *ptos          指向任务堆栈栈顶的指针
                    (INT8U)APP_TASK_START_PRIO,                           //INT8U prio            任务优先级
                    (INT16U)APP_TASK_START_ID,                            //INT16U id             任务的ID号
                    &APP_TaskStartStk[0],                                 //OS_STK *pbos          指向任务堆栈栈底的指针
                    (INT32U)APP_TASK_START_STK_SIZE,                      //INT32U stk_size       堆栈容量
                    (void *)0,                                            //void *pnext           数据指针
                    OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR);           //INT16U opt            设定OSTaskCreateExt的选项

       OSStart();
}

上述例子中,TASK1()OSFLGAPEND()需要第0,1位都置位时才有效,任务刚进来时不满足即被挂起。等待着OSFLGAPOST()把相应位置1。TASK2,TASK3分别把第0,1位置位。即等到执行完TASK3时,TASK1()有效。

2.)若TASK1()如下

static void Task1(void *pdata)
{
    INT8U error;
    INT8U i=0;
    pdata = pdata;
   
    while(1)
    {   
      //若等待事件标志没有发生 该函数并不挂起该任务
       OSFlagAccept(    //请求信号量集
                   Sem_F,
                   (OS_FLAGS)3,   //请求第0位和第1位信号
                   OS_FLAG_WAIT_SET_ALL, //第0位和第1位信号都为1为有效
                    &error
                    );

          //OSFLAGPEND收到有效信号后 在LCD显示字符串 闪两个LED 可以跟据己代码而定
        write_com(0x80+10);
        while(table1[i] != '\0')
        {
          write_dat(table1[i]);
          i++;
        }
       
        GPIO_ResetBits(GPIOD, GPIO_Pin_15);
        GPIO_ResetBits(GPIOD, GPIO_Pin_13);
       
        OSTimeDlyHMSM(0,0,1,0);     //任务挂起1秒 否则优先级低的任务就没机会执行了
       
        GPIO_SetBits(GPIOD, GPIO_Pin_15);
        GPIO_SetBits(GPIOD, GPIO_Pin_13);
        OSTimeDlyHMSM(0,0,1,0);     //让两个LED每秒闪一次
    }
}

即为无等待获取,当信号量不满足,任务也不挂起,即TASK2(),TASK3()不给OSFLAGCCEPT()发送信号,TASK1()仍然执行,在本例中,LCD,LED显示正常。

3.)我们还可以用OSFLGAQUERY()来查询事件标志组的状态。跟据状态来执行自己所期望的代码,用起来很方便且很好。

static void Task1(void *pdata)
{
    INT8U error;
    INT8U i=0,j=0,k=0,Flags;
    pdata = pdata;
   
    while(1)
    {  
       Flags=OSFlagQuery(    //查询事件标志组的状态
           Sem_F,
           &error
           );
       switch(Flags)
       {
       case 1:
            write_com(0x80+10);
            while(table1[i] != '\0')
            {
              write_dat(table1[i]);
              i++;
            }
            break;
        case 2:
            write_com(0x80+0x40);
            while(table2[j] != '\0')
            {
              write_dat(table2[j]);
              j++;
            }
            break;
            case 3:
            write_com(0x80+0x40+8);
            while(table3[k] != '\0')
            {
              write_dat(table3[k]);
              k++;
            }
            break;      
       }
        OSTimeDlyHMSM(0, 0, 1, 0);   //等待2秒  
     
    }
}




              查看评论 回复



嵌入式交流网主页 > 嵌入式操作系统 > UC/OS ii > ucosii解析 uCOS实时操作系统——uCOS事件标志组Flag
 ucosii

"ucosii解析 uCOS实时操作系统——uCOS事件标志组Flag"的相关文章

网站地图

围观()