【FreeRTOS操作系统教程】第26章 FreeRTOS任务事件标志组

标签:
fatfsfreertosstemwinstm32usb |
分类: FreeRTOS |
第26章
FreeRTOS 任务事件标志组
本章节为大家讲解FreeRTOS事件标志组的另一种实现方式----基于任务通知(Task Notifications)的事件标志组,这里我们将这种方式实现的事件标志组称之为任务事件标志组。这种方式实现的事件标志组效率更高,需要的RAM空间更小。当然,缺点也是有的,它没有第18章介绍的事件标志组实现的功能全面。
本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407以及F429。
26.1 任务通知(Task Notifications)介绍
26.2 任务事件标志组
26.3 任务事件标志组API函数
26.4 实验例程说明(任务间通信)
26.5 实验例程说明(中断方式)
26.6
26.1 任务通知(Task
Notifications)介绍
(说明:第24,25,26和27章这部分基础知识是相同的)
FreeRTOS每个已经创建的任务都有一个任务控制块(task control block),任务控制块就是一个结构体变量,用于记录任务的相关信息。结构体变量中有一个32位的变量成员ulNotifiedValue是专门用于任务通知的。
通过任务通知方式可以实现计数信号量,二值信号量,事件标志组和消息邮箱(消息邮箱就是消息队列长度为1的情况)。使用方法与前面章节讲解的事件标志组和信号量基本相同,只是换了不同的函数来实现。任务通知方式实现的计数信号量,二值信号量,事件标志组和消息邮箱是通过修改变量ulNotifiedValue实现的:
(1)设置接收任务控制块中的变量ulNotifiedValue可以实现消息邮箱。
(2)如果接收任务控制块中的变量ulNotifiedValue还没有被其接收到,也可以用新数据覆盖原有数据,这就是覆盖方式的消息邮箱。
(3)设置接收任务控制块中的变量ulNotifiedValue的bit0-bit31数值可以实现事件标志组。
(4)设置接收任务控制块中的变量ulNotifiedValue数值进行加一或者减一操作可以实现计数信号量和二值信号量。
介绍了这么多,那么问题来了,采用这种方式有什么优势呢?根据官方的测试数据,唤醒由于信号量和事件标志组而处于阻塞态的任务,速度提升了45%,而且这种方式需要的RAM空间更小。但这种方式实现的信号量和事件标志组也有它的局限性,主要表现在以下两个方面:
(1)任务通知方式仅可以用在只有一个任务等待信号量,消息邮箱或者事件标志组的情况,不过实际项目项目中这种情况也是最多的
(2)使用任务通知方式实现的消息邮箱替代前面章节讲解的消息队列时,发送消息的任务不支持超时等待,即消息队列中的数据已经满了,可以等待消息队列有空间可以存新的数据,而任务通知方式实现的消息邮箱不支持超时等待。
26.2 任务事件标志组
前面第18章,我们对事件标志组进行了讲解。本章节讲解的任务事件标志组与第18章讲解的事件标志组要实现的功能是一样的,不同的是调用的函数和支持的事件标志个数,任务事件标志组支持32个事件标志设置,而第18章中介绍的事件标志组,每创建一个支持24个事件标志设置:
(1)任务事件标志组的事件标志位是通过任务控制块中的一个32位变量ulNotifiedValue实现。第18章讲解的事件标志组创建后会有自己可以设置的事件标志位。
(2)任务事件标志组是通过函数xTaskNotifyWait()替代第18章讲解的函数xEventGroupWaitBits()实现等待事件标志位被设置。
(3)任务事件标志组是通过函数xTaskNotify()
和 xTaskNotifyFromISR()替代第18章讲解的函数xEventGroupSetBits()
和 xEventGroupSetBitsFromIS
(4)第18章中讲解的函数xEventGroupSetBitsFromIS
具体任务间任务事件标志组的实现过程和中断方式任务事件标志组的实现过程参看第18.1.2小节和18.1.3小节即可。实际项目中,如果使用事件标志组和任务事件标志组都能实现相应功能,强烈建议使用任务事件标志组。
26.3 任务事件标志组API函数
使用如下9个函数可以实现FreeRTOS的任务事件标志组:
(2)
(3)
(4)
(5)
(6)
(7)
(8)
(9)
关于这9个函数的讲解及其使用方法可以看FreeRTOS在线版手册:
这里我们重点的说以下3个函数:
(1)
(2)
(3)
因为本章节配套的例子使用的是这3个函数。
26.3.1
函数xTaskNotify
函数原型:
BaseType_t xTaskNotify( TaskHandle_t xTaskToNotify,
函数描述:
函数xTaskNotify通过设置任务控制块中的变量ulNotifiedValue可以在任务代码中实现任务事件标志组,任务计数信号量,任务消息邮箱和任务二值信号量四种方式的消息通知(见26.1说明)。
u
u
u
u
使用这个函数要注意以下问题:
1.
2.
#define
当然,如果用户不需要使用任务通知功能相关的函数,可以在FreeRTOSConfig.h文件中配置此宏定义为0来禁止,这样创建的每个任务可以节省8个字节的需求。
3.
4.
使用举例:
static TaskHandle_t xHandleTaskMsgPro = NULL;
static void vTaskTaskUserIF(void *pvParameters)
{
}
26.3.2
函数xTaskNotifyFromISR
函数原型:
函数描述:
函数xTaskNotifyFromISR通过设置任务控制块中的变量ulNotifiedValue可以在中断服务程序中实现任务事件标志组,任务计数信号量,任务消息邮箱和任务二值信号量四种方式的消息通知(见26.1说明)。
u
u
u
u
u
使用这个函数要注意以下问题:
1.
2.
#define
当然,如果用户不需要使用任务通知功能相关的函数,可以在FreeRTOSConfig.h文件中配置此宏定义为0来禁止,这样创建的每个任务可以节省8个字节的需求。
3.
4.
使用举例:
static TaskHandle_t xHandleTaskMsgPro = NULL;
static void TIM2_IRQHandler (void)
{
}
26.3.3
函数xTaskNotifyWait
函数原型:
BaseType_t xTaskNotifyWait(
uint32_t
ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t
*pulNotificationValue,
TickType_t
xTicksToWait
);
函数描述:
函数xTaskNotifyWait可以在任务代码中实现任务事件标志组,任务计数信号量,任务消息邮箱和任务二值信号量四种方式的消息获取(见26.1说明)。
u
ulNotifiedValue &= ~ulBitsToClearOnEntry
简单的说就是参数ulBitsToClearOnEntry哪个位是1,那么变量ulNotifiedValue的那个位就会被清零。比如ulBitsToClearOnEntry = 0x01表示将变量ulNotifiedValue的bit0清零,又比如ulBitsToClearOnEntry = 0xffffffff表示将变量ulNotifiedValue的所有位清零。
u
ulNotifiedValue &= ~ ulBitsToClearOnExit
简单的说就是参数ulBitsToClearOnExit哪个位是1,那么变量ulNotifiedValue的那个位就会被清零。比如ulBitsToClearOnExit= 0x01表示将变量ulNotifiedValue的bit0清零,又比如ulBitsToClearOnExit= 0xffffffff表示将变量ulNotifiedValue的所有位清零。
u
u
u
使用这个函数要注意以下问题:
1.
2.
#define
当然,如果用户不需要使用任务通知功能相关的函数,可以在FreeRTOSConfig.h文件中配置此宏定义为0来禁止,这样创建的每个任务可以节省8个字节的需求。
3.
4.
使用举例:
static void vTaskMsgPro(void *pvParameters)
{
}
26.4实验例程说明(任务间通信)
26.4.1STM32F103开发板实验
配套例子:
V4-329_FreeRTOS实验_任务事件标注组
实验目的:
1.
实验内容:
1.
2.
3.
4.
FreeRTOS的配置:
FreeRTOSConfig.h文件中的配置如下:
#if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__)
#endif
#define
configUSE_PREEMPTION
#define
configUSE_IDLE_HOOK
#define
configUSE_TICK_HOOK
#define
configCPU_CLOCK_HZ
#define
configTICK_RATE_HZ
#define
configMAX_PRIORITIES
#define
configMINIMAL_STACK_SIZE
#define
configTOTAL_HEAP_SIZE
#define
configMAX_TASK_NAME_LEN
#define
configUSE_TRACE_FACILITY
#define
configUSE_16_BIT_TICKS
#define
configIDLE_SHOULD_YIELD
#define
configGENERATE_RUN_TIME_STATS
#define
configUSE_STATS_FORMATTING_FUNCTIONS
#define
portCONFIGURE_TIMER_FOR_RUN_TIME_STATS()
#define
portGET_RUN_TIME_COUNTER_VALUE()
//#define
portALT_GET_RUN_TIME_COUNTER_VALUE
#define
configUSE_CO_ROUTINES
#define configMAX_CO_ROUTINE_PRIORITIES ( 2 )
#define
INCLUDE_vTaskPrioritySet
#define
INCLUDE_uxTaskPriorityGet
#define
INCLUDE_vTaskDelete
#define
INCLUDE_vTaskCleanUpResources
#define
INCLUDE_vTaskSuspend
#define
INCLUDE_vTaskDelayUntil
#define
INCLUDE_vTaskDelay
#ifdef __NVIC_PRIO_BITS
#else
#endif
#define
configLIBRARY_LOWEST_INTERRUPT_PRIORITY
#define
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
几个重要选项说明:
u
使能抢占式调度器
u
系统主频72MHz。
u
系统时钟节拍1KHz,即1ms。
u
定义可供用户使用的最大优先级数,如果这个定义的是5,那么用户可以使用的优先级号是0,1,2,3,4,不包含5,对于这一点,初学者要特别的注意。
u
定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。
u
定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。为了进一步说明这个宏定义的的作用,解释如下:
l
l
l
更多关于这个参数说明请参看第12章。
FreeRTOS任务调试信息(按K1按键,串口打印):
上面截图中打印出来的任务状态字母B, R, D, S对应如下含义:
#define
tskBLOCKED_CHAR
#define
tskREADY_CHAR
#define
tskDELETED_CHAR
#define
tskSUSPENDED_CHAR
程序设计:
u
vTaskUserIF任务
vTaskLED任务
vTaskMsgPro任务 :2048字节
vTaskStart任务
任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的
#define
configTOTAL_HEAP_SIZE
u
u
int main(void)
{
}
u
硬件外设的初始化是在bsp.c文件实现:
void bsp_Init(void)
{
}
u
static void AppTaskCreate (void)
{
}
u
static void vTaskTaskUserIF(void *pvParameters)
{
}
static void vTaskLED(void *pvParameters)
{
}
static void vTaskMsgPro(void *pvParameters)
{
}
static void vTaskStart(void *pvParameters)
{
}