我是靠谱客的博主 无限板凳,最近开发中收集的这篇文章主要介绍OSALOSAL,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

OSAL

参考: http://blog.csdn.net/itas109/article/details/12952759

OSAL是一种基于事件驱动的轮询式操作系统

OSAL 的主循环

// 程序的主循环
void osal_start_system( void )
{
#if !defined ( ZBIT ) && !defined ( UBIT )
  for(;;)  // Forever Loop
#endif
  {
    osal_run_system();
  }
}

// 循环的主体
void osal_run_system( void )
{
  uint8 idx = 0;
  // ...
  // 检查各个任务的状态。说明idx越小的任务,优先级别越高。
  do {
    if (tasksEvents[idx])  // Task is highest priority that is ready.
    {
      break;
    }
  } while (++idx < tasksCnt);

  // 有一个任务发生了
  if (idx < tasksCnt)
  {
    uint16 events;
    halIntState_t intState;

    HAL_ENTER_CRITICAL_SECTION(intState);
    events = tasksEvents[idx];
    tasksEvents[idx] = 0;  // Clear the Events for this task.
    HAL_EXIT_CRITICAL_SECTION(intState);

    /* idx为任务的索引(与任务的taskID相同), 根据索引调用对应的任务处理函数 */
    activeTaskID = idx;
    events = (tasksArr[idx])( idx, events ); 
    activeTaskID = TASK_NO_TASK;

    HAL_ENTER_CRITICAL_SECTION(intState);
    tasksEvents[idx] |= events;  // Add back unprocessed events to the current task.
    HAL_EXIT_CRITICAL_SECTION(intState);
  }
#if defined( POWER_SAVING )
  else  // Complete pass through all task events with no activity?
  { // 没有任务发生则休眠
    osal_pwrmgr_powerconserve();  // Put the processor/system into sleep
  }
#endif

  /* Yield in case cooperative scheduling is being used. */
#if defined (configUSE_PREEMPTION) && (configUSE_PREEMPTION == 0)
  {
    osal_task_yield();
  }
#endif
}

Task : 任务

// The order in this table must be identical to the task initialization calls below in osalInitTask.
// tasksArr 存放的是与某个任务相关的处理函数(使用下标对任务进行索引,及下标为0的任务对应的处理函数为Hal_ProcessEvent)
const pTaskEventHandlerFn tasksArr[] = {
  Hal_ProcessEvent,
  App_ProcessEvent
};

// 当前任务的个数
const uint8 tasksCnt = sizeof( tasksArr ) / sizeof( tasksArr[0] );

// 当前任务的状态
uint16 *tasksEvents;

/**
 * @fn      osalInitTasks
 * @brief   This function invokes the initialization function for each task.
 * @param   void
 * @return  none
 * 任务初始化函数,调用所有任务的初始化函数。并为每个任务分配一个taskID。
 */
void osalInitTasks( void )
{
  uint8 taskID = 0;

  tasksEvents = (uint16 *)osal_mem_alloc( sizeof( uint16 ) * tasksCnt);
  osal_memset( tasksEvents, 0, (sizeof( uint16 ) * tasksCnt));

  Hal_Init( taskID++ );
  App_Init( taskID );
}

事件的捕获

以按键时间为例子进行分析。
首先介绍一个函数:osal_set_event, 该函数可以修改某任务的事件变量,提示该任务,某个事件发生了。

uint8 osal_set_event( uint8 task_id, uint16 event_flag )
{
    ...
    tasksEvents[task_id] |= event_flag;  // Stuff the event bit(s)
    ...
}

那么找到这个函数在哪里被调用,不就知道事件是在哪里捕获的了吗。经分析,调用过程如下:

main
    --> InitBoard( OB_READY );
        --> HalKeyConfig(HAL_KEY_INTERRUPT_DISABLE, OnBoard_KeyCallback); // 按键发生时的回调函数是OnBoard_KeyCallback,后面会用到。
            --> osal_set_event(Hal_TaskID, HAL_KEY_EVENT);

    --> osal_start_system(); // 主循环

经过分许发现,在执行osal_start_system 主循环之前,已经注册了一个按键事件 HAL_KEY_EVENT,因此进入主循环后,Hal_ProcessEvent 被调用。

下面分析一下Hal_ProcessEvent函数。其中,osal_start_timerEx这是一个很常用的函数,它在这里的功能是经过100毫秒后,向Hal_TaskID这个ID所标示的任务(也就是其本身)发送一个HAL_KEY_EVENT事件。这样以来,每经过100毫秒,Hal_ProcessEvent这个事件处理函数都会至少执行一次来处理HAL_KEY_EVENT事件。也就是说每隔100毫秒都会执行HalKeyPoll()函数。

// 关键代码
if (events & HAL_KEY_EVENT)
{
     #if (defined HAL_KEY) && (HAL_KEY == TRUE)
     /* Check for keys */
     HalKeyPoll();
     /* if interrupt disabled, do next polling */
     if (!Hal_KeyIntEnable)
     {
             osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);
     }
     #endif // HAL_KEY
     return events ^ HAL_KEY_EVENT;
}

HalKeyPoll 函数首先将按键信息记录在变量keys中,然后传递给了pHalKeyProcessFunction指向的函数。pHalKeyProcessFunction函数是在通过HalKeyConfig(上面有提到)设置的,实际指向的函数为: OnBoard_KeyCallback。

/**
 * @fn      HalKeyPoll
 *
 * @brief   Called by hal_driver to poll the keys
 *
 * @param   None
 *
 * @return  None
 */
void HalKeyPoll (void)
{
  //... 获取按键信息,保存在keys中

  /* Invoke Callback if new keys were depressed */
  if (keys && (pHalKeyProcessFunction))
  {
    (pHalKeyProcessFunction) (keys, HAL_KEY_STATE_NORMAL); // 即调用OnBoard_KeyCallback
  }
}

OnBoard_KeyCallback 函数又做了些什么呢?主要是将按键事件封装成了一个消息(keyChange_t类型),然后调用osal_msg_send将消息放入到消息队列当中。

/**
 * @fn      OnBoard_KeyCallback
 * @brief   Callback service for keys
 * @param   keys  - keys that were pressed
 *          state - shifted
 * @return  void
 */
void OnBoard_KeyCallback ( uint8 keys, uint8 state )
{
  uint8 shift;
  (void)state;

  shift = (keys & HAL_KEY_SW_6) ? true : false;

  if ( OnBoard_SendKeys( keys, shift ) != ZSuccess )
  {
    // Process SW1 here
    if ( keys & HAL_KEY_SW_1 )  // Switch 1
    {

    }
    // Process SW2 here
    if ( keys & HAL_KEY_SW_2 )  // Switch 2
    {
    }
    // Process SW3 here
    if ( keys & HAL_KEY_SW_3 )  // Switch 3
    {
    }
    // Process SW4 here
    if ( keys & HAL_KEY_SW_4 )  // Switch 4
    {
    }
    // Process SW5 here
    if ( keys & HAL_KEY_SW_5 )  // Switch 5
    {
    }
    // Process SW6 here
    if ( keys & HAL_KEY_SW_6 )  // Switch 6
    {

    }
  }
}

/**
 * @fn      OnBoard_SendKeys
 * @brief   Send "Key Pressed" message to application.
 * @param   keys  - keys that were pressed
 *          state - shifted
 * @return  status
 */
uint8 OnBoard_SendKeys( uint8 keys, uint8 state )
{
  keyChange_t *msgPtr;

  if ( registeredKeysTaskID != NO_TASK_ID )
  {
    // Send the address to the task
    msgPtr = (keyChange_t *)osal_msg_allocate( sizeof(keyChange_t) );
    if ( msgPtr )
    {
      msgPtr->hdr.event = KEY_CHANGE;
      msgPtr->state = state;
      msgPtr->keys = keys;

      osal_msg_send( registeredKeysTaskID, (uint8 *)msgPtr );
    }
    return ( ZSuccess );
  }
  else
    return ( ZFailure );
}

消息队列

OSAL维护了一个消息队列(链表),当主循环发现一个事件发生时,便会调用相应的事件处理函数,这些处理函数会从消息队列中获取属于自己的消息(使用函数osal_msg_receive(taskID)来获取某个task的消息),然后调用消息处理函数来处理。

总结

梳理一下整个过程。

  • OSAL在开始主循环时,注册了按键事件的回调函数OnBoard_KeyCallback、并放入了一个HAL_KEY_EVENT事件。
  • 然后OSAL进入了主循环。不断轮询,查看有没有时间发生。因为第1步中,OSAL自己放入了一个HAL_KEY_EVENT事件,所以对应的处理函数Hal_ProcessEvent被触发。该函数使用osal_start_timerEx( Hal_TaskID, HAL_KEY_EVENT, 100);HalKeyPoll 每100毫秒被执行一次。(也就是说,Hal_ProcessEvent第一次被调用是应为OSAL自己放入了一个事件;而之后,是通过timer进行定时调用)
    • HalKeyPoll会检查有哪些按键被按下了,然后调用OnBoard_KeyCallback, 将该按键事件封装成一个消息,并放入到消息队列当中,同时会给消息加上SYS_EVENT_MSG。(所以该按键事件会在下次调用Hal_ProcessEvent时被处理)。
    • Hal_ProcessEvent函数检测到event中有SYS_EVENT_MSG时,会调用osal_msg_receive从消息队列中取出消息进行处理。

最后

以上就是无限板凳为你收集整理的OSALOSAL的全部内容,希望文章能够帮你解决OSALOSAL所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(70)

评论列表共有 0 条评论

立即
投稿
返回
顶部