FreeRTOS学习笔记7——EventGroups
FreeRTOS Note for EventGroup
FreeRTOS Note for EventGroup
Event Group特性
利用Event Group 管理事件
xEventGroupCreate()
xEventGroupSetBits()
xEventGroupSetBitsFromISR()
xEventGroupWaitBits()
例程
Event Group用于task 同步
xEventGroupSync
例程
Event Group特性
利用Event Group 管理事件
xEventGroupCreate()
xEventGroupSetBits()
xEventGroupSetBitsFromISR()
xEventGroupWaitBits()
例程
Event Group用于task 同步
xEventGroupSync
例程
Event Group特性
eeRTOSConfig.h
configUSE_16_BIT_TICKS
设置为1时,每个event group 有8个可用的event bitsconfigUSE_16_BIT_TICKS
设置为0时,每个event group 有24个可用的event bits
利用Event Group 管理事件
xEventGroupCreate()
FreeRTOS9.0 引入API: xEventGroupCreateStatic(),用于静态创建event group
EventGroupHandle_t xEventGroupCreate( void );
xEventGroupSetBits()
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet );
xEventGroupSetBitsFromISR()
BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
BaseType_t *pxHigherPriorityTaskWoken );
xEventGroupWaitBits()
EventBits_t xEventGroupWaitBits( const EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait );
例程
/* Definitions for the event bits in the event group. */
#define mainFIRST_TASK_BIT ( 1UL << 0UL ) /* Event bit 0, which is set by a task. */
#define mainSECOND_TASK_BIT ( 1UL << 1UL ) /* Event bit 1, which is set by a task. */
#define mainISR_BIT ( 1UL << 2UL ) /* Event bit 2, which is set by an ISR. */
static void vEventBitSettingTask( void *pvParameters )
{
const TickType_t xDelay200ms = pdMS_TO_TICKS( 200UL ), xDontBlock = 0;
for( ;; )
{
/* Delay for a short while before starting the next loop. */
vTaskDelay( xDelay200ms );
/* Print out a message to say event bit 0 is about to be set by the task,
then set event bit 0\. */
vPrintString( "Bit setting task -\t about to set bit 0.\r\n" );
xEventGroupSetBits( xEventGroup, mainFIRST_TASK_BIT );
/* Delay for a short while before setting the other bit. */
vTaskDelay( xDelay200ms );
/* Print out a message to say event bit 1 is about to be set by the task,
then set event bit 1\. */
vPrintString( "Bit setting task -\t about to set bit 1.\r\n" );
xEventGroupSetBits( xEventGroup, mainSECOND_TASK_BIT );
}
}
static uint32_t ulEventBitSettingISR( void )
{
/* The string is not printed within the interrupt service routine, but is instead
sent to the RTOS daemon task for printing. It is therefore declared static to ensure
the compiler does not allocate the string on the stack of the ISR, as the ISR's stack
frame will not exist when the string is printed from the daemon task. */
static const char *pcString = "Bit setting ISR -\t about to set bit 2.\r\n";
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* Print out a message to say bit 2 is about to be set. Messages cannot be
printed from an ISR, so defer the actual output to the RTOS daemon task by
pending a function call to run in the context of the RTOS daemon task. */
xTimerPendFunctionCallFromISR( vPrintStringFromDaemonTask,
( void * ) pcString,
0,
&xHigherPriorityTaskWoken );
/* Set bit 2 in the event group. */
xEventGroupSetBitsFromISR( xEventGroup, mainISR_BIT, &xHigherPriorityTaskWoken );
/* xTimerPendFunctionCallFromISR() and xEventGroupSetBitsFromISR() both write to
the timer command queue, and both used the same xHigherPriorityTaskWoken
variable. If writing to the timer command queue resulted in the RTOS daemon task
leaving the Blocked state, and if the priority of the RTOS daemon task is higher
than the priority of the currently executing task (the task this interrupt
interrupted) then xHigherPriorityTaskWoken will have been set to pdTRUE.
.
xHigherPriorityTaskWoken is used as the parameter to portYIELD_FROM_ISR(). If
xHigherPriorityTaskWoken equals pdTRUE, then calling portYIELD_FROM_ISR() will
request a context switch. If xHigherPriorityTaskWoken is still pdFALSE, then
calling portYIELD_FROM_ISR() will have no effect.
The implementation of portYIELD_FROM_ISR() used by the Windows port includes a
return statement, which is why this function does not explicitly return a
value. */
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
static void vEventBitReadingTask( void *pvParameters )
{
EventBits_t xEventGroupValue;
const EventBits_t xBitsToWaitFor = ( mainFIRST_TASK_BIT |
mainSECOND_TASK_BIT |
mainISR_BIT );
for( ;; )
{
/* Block to wait for event bits to become set within the event group. */
xEventGroupValue = xEventGroupWaitBits( /* The event group to read. */
xEventGroup,
/* Bits to test. */
xBitsToWaitFor,
/* Clear bits on exit if the
unblock condition is met. */
pdTRUE,
/* Don't wait for all bits. This
parameter is set to pdTRUE for the
second execution. */
pdFALSE,
/* Don't time out. */
portMAX_DELAY );
/* Print a message for each bit that was set. */
if( ( xEventGroupValue & mainFIRST_TASK_BIT ) != 0 )
{
vPrintString( "Bit reading task -\t Event bit 0 was set\r\n" );
}
if( ( xEventGroupValue & mainSECOND_TASK_BIT ) != 0 )
{
vPrintString( "Bit reading task -\t Event bit 1 was set\r\n" );
}
if( ( xEventGroupValue & mainISR_BIT ) != 0 )
{
vPrintString( "Bit reading task -\t Event bit 2 was set\r\n" );
}
}
}
int main( void )
{
/* Before an event group can be used it must first be created. */
xEventGroup = xEventGroupCreate();
/* Create the task that sets event bits in the event group. */
xTaskCreate( vEventBitSettingTask, "Bit Setter", 1000, NULL, 1, NULL );
/* Create the task that waits for event bits to get set in the event group. */
xTaskCreate( vEventBitReadingTask, "Bit Reader", 1000, NULL, 2, NULL );
/* Create the task that is used to periodically generate a software interrupt. */
xTaskCreate( vInterruptGenerator, "Int Gen", 1000, NULL, 3, NULL );
/* Install the handler for the software interrupt. The syntax necessary to do
this is dependent on the FreeRTOS port being used. The syntax shown here can
only be used with the FreeRTOS Windows port, where such interrupts are only
simulated. */
vPortSetInterruptHandler( mainINTERRUPT_NUMBER, ulEventBitSettingISR );
/* Start the scheduler so the created tasks start executing. */
vTaskStartScheduler();
/* The following line should never be reached. */
for( ;; );
return 0;
}
Event Group用于task 同步
xEventGroupSync
EventBits_t xEventGroupSync( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet,
const EventBits_t uxBitsToWaitFor,
TickType_t xTicksToWait );
例程
static void vSyncingTask( void *pvParameters )
{
const TickType_t xMaxDelay = pdMS_TO_TICKS( 4000UL );
const TickType_t xMinDelay = pdMS_TO_TICKS( 200UL );
TickType_t xDelayTime;
EventBits_t uxThisTasksSyncBit;
const EventBits_t uxAllSyncBits = ( mainFIRST_TASK_BIT |
mainSECOND_TASK_BIT |
mainTHIRD_TASK_BIT );
/* Three instances of this task are created - each task uses a different event
bit in the synchronization. The event bit to use is passed into each task
instance using the task parameter. Store it in the uxThisTasksSyncBit
variable. */
uxThisTasksSyncBit = ( EventBits_t ) pvParameters;
for( ;; )
{
/* Simulate this task taking some time to perform an action by delaying for a
pseudo random time. This prevents all three instances of this task reaching
the synchronization point at the same time, and so allows the example’s
behavior to be observed more easily. */
xDelayTime = ( rand() % xMaxDelay ) + xMinDelay;
vTaskDelay( xDelayTime );
/* Print out a message to show this task has reached its synchronization
point. pcTaskGetTaskName() is an API function that returns the name assigned
to the task when the task was created. */
vPrintTwoStrings( pcTaskGetTaskName( NULL ), "reached sync point" );
/* Wait for all the tasks to have reached their respective synchronization
points. */
xEventGroupSync( /* The event group used to synchronize. */
xEventGroup,
/* The bit set by this task to indicate it has reached the
synchronization point. */
uxThisTasksSyncBit,
/* The bits to wait for, one bit for each task taking part
in the synchronization. */
uxAllSyncBits,
/* Wait indefinitely for all three tasks to reach the
synchronization point. */
portMAX_DELAY );
/* Print out a message to show this task has passed its synchronization
point. As an indefinite delay was used the following line will only be
executed after all the tasks reached their respective synchronization
points. */
vPrintTwoStrings( pcTaskGetTaskName( NULL ), "exited sync point" );
}
}
/* Definitions for the event bits in the event group. */
#define mainFIRST_TASK_BIT ( 1UL << 0UL ) /* Event bit 0, set by the first task. */
#define mainSECOND_TASK_BIT( 1UL << 1UL ) /* Event bit 1, set by the second task. */
#define mainTHIRD_TASK_BIT ( 1UL << 2UL ) /* Event bit 2, set by the third task. */
/* Declare the event group used to synchronize the three tasks. */
EventGroupHandle_t xEventGroup;
int main( void )
{
/* Before an event group can be used it must first be created. */
xEventGroup = xEventGroupCreate();
/* Create three instances of the task. Each task is given a different name,
which is later printed out to give a visual indication of which task is
executing. The event bit to use when the task reaches its synchronization point
is passed into the task using the task parameter. */
xTaskCreate( vSyncingTask, "Task 1", 1000, mainFIRST_TASK_BIT, 1, NULL );
xTaskCreate( vSyncingTask, "Task 2", 1000, mainSECOND_TASK_BIT, 1, NULL );
xTaskCreate( vSyncingTask, "Task 3", 1000, mainTHIRD_TASK_BIT, 1, NULL );
/* Start the scheduler so the created tasks start executing. */
vTaskStartScheduler();
/* As always, the following line should never be reached. */
for( ;; );
return 0;
}