FreeRTOS的事件组和任务通知源码分析

一、事件组和任务通知介绍

事件组可以用来广播,当事件发生时,所有符合条件的任务都会被唤醒;任务通知时高效的任务间通信方式,但是只能给单个任务发送单个数据。

二、关键结构体

typedef struct xEventGroupDefinition
{
  EventBits_t uxEventBits;              // 一个整数,每个bit表示一个事件
  List_t xTasksWaitingForBits;          // 等待事件发生的task挂在这个队列上
} EventGroup_t;

三、事件组创建和删除函数

// 创建
EventGroupHandle_t xEventGroupCreate( void )
{
  EventGroup_t *pxEventBits;
  pxEventBits = ( EventGroup_t * ) pvPortMalloc( sizeof( EventGroup_t ) );    // 分配空间
  pxEventBits->uxEventBits = 0;      // 设置uxEventBits
  vListInitialise( &( pxEventBits->xTasksWaitingForBits ) );  // 初始化队列
  return ( EventGroupHandle_t ) pxEventBits;    // 返回句柄
}
// 删除
void vEventGroupDelete( EventGroupHandle_t xEventGroup )
{
  EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
  const List_t *pxTasksWaitingForBits = &( pxEventBits->xTasksWaitingForBits );
  vTaskSuspendAll();      // 停止任务
  while( listCURRENT_LIST_LENGTH( pxTasksWaitingForBits ) > ( UBaseType_t ) 0 )        // 如果删除时还有任务在等待事件发生
  {  
    vTaskRemoveFromUnorderedEventList( pxTasksWaitingForBits->xListEnd.pxNext, eventUNBLOCKED_DUE_TO_BIT_SET );  // 将任务遍历移除
  }
  vPortFree( pxEventBits );    // 释放空间
  ( void ) xTaskResumeAll();    // 任务开始
}

四、事件组设置事件和等待事件

EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet )
{
  List_t *pxList;
  BaseType_t xMatchFound = pdFALSE;
  EventGroup_t *pxEventBits = ( EventGroup_t * ) xEventGroup;
  pxList = &( pxEventBits->xTasksWaitingForBits );      // 等待队列
  pxListEnd = listGET_END_MARKER( pxList );             // 队列尾
  vTaskSuspendAll();      // 停止任务
  pxListItem = listGET_HEAD_ENTRY( pxList );            // 队列头
  pxEventBits->uxEventBits |= uxBitsToSet;              // 设置bit
  while( pxListItem != pxListEnd )    // 遍历
  {
    pxNext = listGET_NEXT( pxListItem );
    ...                // 寻找uxBitsToClear
    pxListItem = pxNext;
  }
  pxEventBits->uxEventBits &= ~uxBitsToClear;            // 清空bit
  ( void ) xTaskResumeAll();  // 开始任务
  return pxEventBits->uxEventBits;
}
EventBits_t xEventGroupWaitBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToWaitFor, const BaseType_t xClearOnExit, const BaseType_t xWaitForAllBits, TickType_t xTicksToWait )
{
}

五、任务发出通知

#define xTaskNotifyGive( xTaskToNotify ) xTaskGenericNotify( ( xTaskToNotify ), ( 0 ), eIncrement, NULL )
BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue )
{
  TCB_t * pxTCB;      // 任务的TCB结构体,传入参数xTaskToNotify
  BaseType_t xReturn = pdPASS;
  uint8_t ucOriginalNotifyState;  // 记录通知状态 
  pxTCB = ( TCB_t * ) xTaskToNotify;
  taskENTER_CRITICAL();      // 关中断
  ucOriginalNotifyState = pxTCB->ucNotifyState;  // 记录原始通知状态
  pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;    // 当前任务接收到通知,pending
  switch( eAction )
  {
    case eSetBits	:
      pxTCB->ulNotifiedValue |= ulValue;      // 设置通知值bit
      break;
    case eIncrement	:
      ( pxTCB->ulNotifiedValue )++;           // 通知值计数值++
      break;
    case eSetValueWithOverwrite :
      pxTCB->ulNotifiedValue = ulValue;       // 覆写通知值
      break;
    case eSetValueWithoutOverwrite :          
      if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
      {
        pxTCB->ulNotifiedValue = ulValue;
      }
      else
      {
        xReturn = pdFAIL;                // 原来有值,写失败
      }
      break;
    case eNoAction:
      break;                            // 什么也不做
  }
  if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )        // 如果被通知的任务原来在等待通知状态
  {
    ( void ) uxListRemove( &( pxTCB->xStateListItem ) );        // 将任务从等待状态改变list移除
    prvAddTaskToReadyList( pxTCB );                             // 加入就绪队列
    if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )          // 如果被唤醒任务的优先级更高
    {
      taskYIELD_IF_USING_PREEMPTION();                          // 重新调度
    }
  }
  taskEXIT_CRITICAL();                                          // 开中断
  return xReturn;
}

六、任务取出通知

uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait )
{
  uint32_t ulReturn;
  taskENTER_CRITICAL();    // 关中断
  if( pxCurrentTCB->ulNotifiedValue == 0UL )        // 正在执行的任务通知值为0
  {
    pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;    // 标记状态为等待通知
    if( xTicksToWait > ( TickType_t ) 0 )           // 有设置等待时间
    {
      prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );  // 将当前任务加入等待list
      portYIELD_WITHIN_API();      // 调度
    }
  }
  taskEXIT_CRITICAL();      // 开中断
  taskENTER_CRITICAL();     // 关中断
  ulReturn = pxCurrentTCB->ulNotifiedValue;    // 记录当前的通知值
  if( ulReturn != 0UL )    // 接收到通知
  {
    if( xClearCountOnExit != pdFALSE )  // 函数返回前清0标志
    {
      pxCurrentTCB->ulNotifiedValue = 0UL;
    }
    else
    {
      pxCurrentTCB->ulNotifiedValue = ulReturn - ( uint32_t ) 1;   // 值减1 
    }
  }
  pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;    // 重设task的通知状态为等待接收通知
  taskEXIT_CRITICAL();     // 开中断
  return ulReturn;         // 返回收到通知后得我通知值
}
posted @ 2025-07-14 20:56  gramming  阅读(285)  评论(0)    收藏  举报