1 FreeRTOS中事件的理解
事件是一种实现任务间通信的机制,主要用于实现多任务间的同步,但事件通信只能是事件类型的通信,无数据传输。与信号量不同的是,它可以实现一对多,多对多的同步。即一个任务可以等待多个事件的发生:可以是任意一个事件发生时唤醒任务进行事件处理;也可以是几个事件都发生后才唤醒任务进行事件处理。同样,也可以是多个任务同步多个事件。
2 事件的运作机制
应用一个实例来解释,更加易懂。
任务1对事件3或事件5感兴趣(逻辑或),当发生其中的某一个事件都会被唤醒,并且执行相应操作。而任务2对事件3与事件5感兴趣(逻辑与),当且仅当事件3与事件5都发生的时候,任务2才会被唤醒,如果只有一个其中一个事件发生,那么任务还是会继续等待事件发生。如果接在收事件函数中设置了清除事件位xClearOnExit,那么当任务唤醒后将把事件3和事件5的事件标志清零,否则事件标志将依然存在。
3 编写事件主要步骤
3.1 创建事件
FreeRTOS给我们提供了一个创建事件的函数xEventGroupCreate(),当创建一个事件时,系统会首先给我们分配事件控制块的内存空间,然后对该事件控制块进行基本的初始化,创建成功返回事件句柄;创建失败返回NULL。所以,在使用创建函数之前,我们需要先定义有个事件的句柄。
3.2 事件组置位
xEventGroupSetBits()用于置位事件组中指定的位,当位被置位之后,阻塞在该位上的任务将会被解锁。使用该函数接口时,通过参数指定的事件标志来设定事件的标志位,然后遍历等待在事件对象上的事件等待列表,判断是否有任务的事件激活要求与当前事件对象标志值匹配,如果有,则唤醒该任务。简单来说,就是设置我们自己定义的事件标志位为1,并且看看有没有任务在等待这个事件,有的话就唤醒它。
EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToSet );
xEventGroup:事件句柄;
uxBitsToSet:指定事件中的事件标志位。如设置uxBitsToSet为0x08则只置位位3,如果设置uxBitsToSet为0x09则位3和位0 都需要被置位;
返回值: 返回调用xEventGroupSetBits() 时事件组中的值。
3.3 事件等待
FreeRTOS提供了一个等待指定事件的函数——xEventGroupWaitBits(),通过这个函数,任务可以知道事件标志组中的哪些位,有什么事件发生了,然后通过 “逻辑与”、“逻辑或”等操作对感兴趣的事件进行获取,并且这个函数实现了等待超时机制,当且仅当任务等待的事件发生时,任务才能获取到事件信息。在这段时间中,如果事件一直没发生,该任务将保持阻塞状态以等待事件发生。EventGroupWaitBits()用于获取事件组中的一个或多个事件发生标志,当要读取的事件标志位没有被置位时任务将进入阻塞等待状态。
EventBits_t xEventGroupWaitBits( const EventGroupHandle_t xEventGroup,
const EventBits_t uxBitsToWaitFor,
const BaseType_t xClearOnExit,
const BaseType_t xWaitForAllBits,
TickType_t xTicksToWait );
xEventGroup:事件句柄;
uxBitsToWaitFor:一个按位或的值,指定需要等待事件组中的哪些位置1。如果需要等待bit 0 and/or bit 2那么uxBitsToWaitFor 配置为0x05(0101b)。如果需要等待bits 0 and/or bit 1 and/or bit 2那么uxBitsToWaitFor配置为0x07(0111b);
xClearOnExit:pdTRUE:当xEventGroupWaitBits()等待到满足任务唤醒的事件时,系统将清除由形参uxBitsToWaitFor指定的事件标志位;
pdFALSE:不会清除由形参uxBitsToWaitFor指定的事件标志位;
xWaitForAllBits:pdTRUE:当形参uxBitsToWaitFor指定的位都置位的时候,xEventGroupWaitBits()才满足任务唤醒的条件,这也是“逻辑与”等待事件,并且在没有超时的情况下返回对应的事件标志位的值;pdFALSE:当形参uxBitsToWaitFor指定的位有其中任意一个置位的时候,这也是常说的“逻辑或”等待事件,在没有超时的情况下函数返回对应的事件标志位的值;
xTicksToWait:最大超时时间,单位为系统节拍周期,常量portTICK_PERIOD_MS用于辅助把时间转换成MS;
返回值: 返回事件中的哪些事件标志位被置位,返回值很可能并不是用户指定的事件位,需要对返回值进行判断再处理。
4 实验结果
打印的显示截图如下:
/***
*****************************************************************************************
主程序和各个任务程序,截取程序主要部分,各个文件的句柄放在头文件里面的,需要读者自己加入
就行了,最好再声明一下任务函数,另外我发现程序转过来后注释全成了乱码,但是不影响程序运行
*****************************************************************************************
**
*/
static void KEY_Task(void* parameter)
{
while(1)
{
if(Key_Scan(KEY1_GPIO_PORT, KEY1_GPIO_PIN)==KEY_ON)
{
printf("KEY1±»°´ÏÂ\n");
xEventGroupSetBits( Event_Handle, KEY1_EVENT );
}
vTaskDelay(10);
}
}
static void LED3_Task(void* parameter)
{
EventBits_t R_event;
while(1)
{
R_event= xEventGroupWaitBits( Event_Handle,
KEY1_EVENT,
pdTRUE,
pdTRUE,
portMAX_DELAY);
printf("½ÓÊܵ½Ê¼þKEY1_EVENT\n");
if( R_event==KEY1_EVENT)
{
LED3_ON;
vTaskDelay(500);
LED3_OFF;
}
}
}
static void AppTaskCreate(void)
{
BaseType_t xReturn=pdPASS;
taskENTER_CRITICAL();
Event_Handle=xEventGroupCreate();
if(NULL!= Event_Handle)
printf("Event_Handleʼþ´´½¨Íê³É\n");
xReturn = xTaskCreate( (TaskFunction_t)KEY_Task,
(const char*)"KEY_Task",
(uint32_t)128 ,
(void *) NULL,
(UBaseType_t) 4,
(TaskHandle_t *) &KEY_Task_Handle);
if(pdPASS==xReturn)
printf ("KEY_Task founded successfully by bieber\n");
else
printf("KEY_Task founded failed by biebier\n");
/* ½¨Á¢ÈÎÎñLED3_Task */
xReturn = xTaskCreate( (TaskFunction_t)LED3_Task,
(const char*)"LED3_Task",
(uint32_t)128 ,
(void *) NULL,
(UBaseType_t) 5,
(TaskHandle_t *)&LED3_Task_Handle);
if(pdPASS==xReturn)
printf ("LED3_Task founded successfully by bieber\n");
else
printf("LED3_Task founded failed by biebier\n");
vTaskDelete(AppTaskCreate_Handle);
taskEXIT_CRITICAL();
}
int main(void)
{
BaseType_t xReturn=pdPASS;
BSP_Init();
printf(" ²âÊÔ³ÌÐò¿ªÊ¼ \n");
xReturn = xTaskCreate( (TaskFunction_t) AppTaskCreate,
(const char *)"APPTaskCreate",
(uint32_t)512 ,
(void *) NULL,
(UBaseType_t) 1,
(TaskHandle_t *)&AppTaskCreate_Handle);
if(pdPASS== xReturn)
vTaskStartScheduler();
else
return -1;
while(1);
}