creep 发表于 2017-4-18 22:53:51

【NUCLEO-L496ZG评测】+ UCOSIII:任务内建信号量和消息队列


   和UCOSII相比UCOSIII做了很多改进和提升,特别是在内核性能方面,比如任务内建信号量和消息队列。UCOSIII任务内建信号量允许ISR或者任务直接发送信号量给其他的任务,这样避免了创建一个中间级的内核对象-信号量只用来标记一个单独的任务,同样UCOSIII任务内建的消息队列也可以从ISR或者任务直接发送消息给另外一个任务。

   通过分析UCOSIII的任务级的时基处理代码可以很好的了解任务内建信号量和消息队列的用法。在初始化OS的时候会定一个事件任务,该任务的优先级默认为1(数字越低优先级越高)。通常情况下UCOSIII第一次调度会进入这个任务。


   
OSTaskCreate((OS_TCB   *)&OSTickTaskTCB,
               (CPU_CHAR   *)((void *)"uC/OS-III Tick Task"),
               (OS_TASK_PTR )OS_TickTask,
               (void       *)0,
               (OS_PRIO   )OSCfg_TickTaskPrio,
               (CPU_STK    *)OSCfg_TickTaskStkBasePtr,
               (CPU_STK_SIZE)OSCfg_TickTaskStkLimit,
               (CPU_STK_SIZE)OSCfg_TickTaskStkSize,
               (OS_MSG_QTY)0u,
               (OS_TICK   )0u,
               (void       *)0,
               (OS_OPT      )(OS_OPT_TASK_STK_CHK | OS_OPT_TASK_STK_CLR | OS_OPT_TASK_NO_TLS),
               (OS_ERR   *)p_err);时基任务的代码如下:任务信号量pend的调用直接使用OSTaskSemPend()即可。和创建内核信号量的pend函数相比省略了第一个信号量定义的参数。在进入该函数之后如果没有请求到信号量就会被阻塞。

voidOS_TickTask (void*p_arg)
{
    OS_ERRerr;
    CPU_TSts_delta;
    CPU_TSts_delta_dly;
    CPU_TSts_delta_timeout;
    CPU_SR_ALLOC();


    (void)&p_arg;                                             /* Prevent compiler warning                           */

    while (DEF_ON) {
      (void)OSTaskSemPend((OS_TICK)0,
                            (OS_OPT   )OS_OPT_PEND_BLOCKING,
                            (CPU_TS*)0,
                            (OS_ERR*)&err);                   /* Wait for signal from tick interrupt                  */
      if (err == OS_ERR_NONE) {
            OS_CRITICAL_ENTER();
            OSTickCtr++;                                        /* Keep track of the number of ticks                  */
#if (defined(TRACE_CFG_EN) && (TRACE_CFG_EN > 0u))
            TRACE_OS_TICK_INCREMENT(OSTickCtr);               /* Record the event.                                    */
#endif
            OS_CRITICAL_EXIT();
            ts_delta_dly   = OS_TickListUpdateDly();
            ts_delta_timeout = OS_TickListUpdateTimeout();
            ts_delta         = ts_delta_dly + ts_delta_timeout; /* Compute total execution time of list updates         */
            if (OSTickTaskTimeMax < ts_delta) {
                OSTickTaskTimeMax = ts_delta;
            }
      }
    }
}在时基中断函数中OSTimeTick()进行了时基任务的信号量post,同时也进行了软件定时器任务型号的post,这个函数驱动了UCOSIII的调度和软件定时器。

voidOSTimeTick (void)
{
    OS_ERRerr;

    OSTimeTickHook();                                       /* Call user definable hook                               */


   (void)OSTaskSemPost((OS_TCB *)&OSTickTaskTCB,            /* Signal tick task                                       */
                     (OS_OPT) OS_OPT_POST_NONE,
                     (OS_ERR *)&err);

   (void)err;

#if OS_CFG_SCHED_ROUND_ROBIN_EN > 0u
    OS_SchedRoundRobin(&OSRdyList);
#endif

#if OS_CFG_TMR_EN > 0u
    OSTmrUpdateCtr--;
    if (OSTmrUpdateCtr == (OS_CTR)0u) {
      OSTmrUpdateCtr = OSTmrUpdateCnt;
      OSTaskSemPost((OS_TCB *)&OSTmrTaskTCB,            /* Signal timer task                                    */
                      (OS_OPT) OS_OPT_POST_NONE,
                      (OS_ERR *)&err);
    }
#endif

}1、任务内建信号量


我们将前面的创建的内核信号量的例子修改为使用任务的信号量来测试。


在任务中直接调用任务的信号量pend函数:

在按键函数中post函数中:

信号量的post和pend地方都和之前的一样只是调用的函数略有不同。
测试如下:



2、任务内建消息队列
同样的将之前的消息队列的例子稍加修改即可使用任务内建消息队列进行传输。
消息队列的post和pend分别如下:




post 消息



测试如下。消息队列超过12个也会提示内存不足。




对于同步单个任务的信号量或者和单个任务进行通信的消息队列,使用任务内建的信号量和消息队列非常的简单方便。除此之外UCOSIII比UCOSII还有很多的提示,通过研究UCOSIII的源代码我们可以更加详细的了解这种不同进而更加的熟练的掌握这个OS。


测试代码:




推荐阅读:

【NUCLEO-L496ZG评测】+ UCOSIII:内存管理和消息队列

【NUCLEO-L496ZG评测】+ UCOSIII:软件定时器和信号量

【NUCLEO-L496ZG评测】+ UCOSIII简单移植


【NUCLEO-L496ZG评测】+ UCOSIII:事件标志组






any012 发表于 2017-4-19 10:07:43

很好的帖子,先标记下,顶起来。
页: [1]
查看完整版本: 【NUCLEO-L496ZG评测】+ UCOSIII:任务内建信号量和消息队列