完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
第18章 FreeRTOS事件标志组 前面的章节我们已经讲解了任务管理和时间管理,从本章节开始讲解任务间的通信和同步机制。首先讲解任务间的通信和同步机制之一,事件标志组。 本章教程配套的例子含Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407以及F429。 18.1 事件标志组 18.2 事件标志组API函数 18.3 实验例程说明(任务间通信) 18.4 实验例程说明(中断方式通信) 18.5 总结 18.1 事件标志组 18.1.1 为什么要使用事件标志 事件标志组是实现多任务同步的有效机制之一。也许有不理解的初学者会问采用事件标志组多麻烦,搞个全局变量不是更简单?其实不然,在裸机编程时,使用全局变量的确比较方便,但是在加上RTOS后就是另一种情况了。使用全局变量相比事件标志组主要有如下三个问题: 1、使用事件标志组可以让RTOS内核有效地管理任务,而全局变量是无法做到的,任务的超时等机制需要用户自己去实现。 2、使用了全局变量就要防止多任务的访问冲突,而使用事件标志组则处理好了这个问题,用户无需担心。 3、使用事件标志组可以有效地解决中断服务程序和任务之间的同步问题。 18.1.2 FreeRTOS任务间事件标志组的实现 任务间事件标志组的实现是指各个任务之间使用事件标志组实现任务的通信或者同步机制。 下面我们来说说FreeRTOS中事件标志的实现,根据用户在FreeRTOSConfig.h文件中的配置: 1、#define configUSE_16_BIT_tiCKS 1 配置宏定义configUSE_16_BIT_TICKS为1时,每创建一个事件标志组,用户可以使用的事件标志是8个。 2、#define configUSE_16_BIT_TICKS 0 配置宏定义configUSE_16_BIT_TICKS为0时,每创建一个事件标志组,用户可以使用的事件标志是24个。 |
|
相关推荐
|
|
上面说的8个和24个事件标志应该怎么理解呢?其实就是定义了一个16位变量,仅使用了低8bit或者定义了一个32位变量,仅使用了低24bit。每一个bit用0和1两种状态来代表事件标志。反映到FreeRTOS上就是将事件标志存储到了EventBits_t类型的变量中,这个变量又是怎么回事呢?定义如下:
复制代码 /* * The type that holds event bits always matches TickType_t - therefore the * number of bits it holds is set by configUSE_16_BIT_TICKS (16 bits if set to 1, * 32 bits if set to 0. * * defgroup EventBits_t EventBits_t * ingroup EventGroup */ typedef TickType_t EventBits_t; 进一步跟踪TickType_t的数据类型,定义如下: 复制代码 #if( configUSE_16_BIT_TICKS == 1 ) typedef uint16_t TickType_t; #define portMAX_DELAY ( TickType_t ) 0xffff #else typedef uint32_t TickType_t; #define portMAX_DELAY ( TickType_t ) 0xffffffffUL /* 32-bit tick type on a 32-bit architecture, so reads of the tick count do not need to be guarded with a critical section. */ #define portTICK_TYPE_IS_ATOMIC 1 #endif |
|
|
|
|
|
由上面定义可以看出,TickType_t数据类型可以是16位数或者32位数,这样就跟上面刚刚说的configUSE_16_BIT_TICKS 宏定义呼应上了。教程配套的例子都是配置宏定义configUSE_16_BIT_TICKS为0,即用户每创建一个事件标志组,有24个标志可以设置。如下图所示,这里仅使用bit0,bit1和bit2。
注意:后面的讲解中,默认全是创建一个事件标志,支持24个事件标志设置。 下面我们通过如下的框图来说明一下FreeRTOS事件标志的实现,让大家有一个形象的认识。 运行条件: (1)创建2个任务:Task1和Task2 运行过程描述如下: (1)任务Task1运行过程中调用函数xEventGroupWaitBits,等待事件标志位被设置,任务Task1由运行态进入到阻塞态。 (2)任务Task2设置Task1等待的事件标志,任务Task1由阻塞态进入到就绪态,在调度器的作用下由就绪态又进入到运行态。 上面就是一个简单的FreeRTOS任务间事件标志通信过程。 |
|
|
|
|
|
18.1.3 FreeRTOS中断方式事件标志组的实现
FreeRTOS中断方式事件标志组的实现是指中断函数和FreeRTOS任务之间使用事件标志。下面我们通过如下的框图来说明一下FreeRTOS事件标志的实现,让大家有一个形象的认识。 运行条件: (1)创建一个任务和一个串口接收中断 运行过程描述如下: (1)任务Task1运行过程中调用函数xEventGroupWaitBits,等待事件标志位被设置,任务Task1由运行态进入到阻塞态。 (2)Task1阻塞的情况下,串口接收到数据进入到了串口中断服务程序,在串口中断服务程序中设置Task1等待的事件标志,任务Task1由阻塞态进入到就绪态,在调度器的作用下由就绪态又进入到运行态。 上面就是一个简单的FreeRTOS中断方式事件标志通信过程。实际应用中,中断方式的消息机制要注意以下四个问题: (1)中断函数的执行时间越短越好,防止其它低于这个中断优先级的异常不能得到及时响应。 (2)实际应用中,建议不要在中断中实现消息处理,用户可以在中断服务程序里面发送消息通知任务,在任务中实现消息处理,这样可以有效地保证中断服务程序的实时响应。同时此任务也需要设置为高优先级,以便退出中断函数后任务可以得到及时执行。 (3)中断服务程序中一定要调用专用于中断的事件标志设置函数,即以FromISR结尾的函数。 (4)在操作系统中实现中断服务程序与裸机编程的区别。 A. 如果FreeRTOS工程的中断函数中没有调用FreeRTOS的事件标志组API函数,与裸机编程是一样的。 B. 如果FreeRTOS工程的中断函数中调用了FreeRTOS的事件标志组的API函数,退出的时候要检测是否有高优先级任务就绪,如果有就绪的,需要在退出中断后进行任务切换,这点跟裸机编程稍有区别,详见18.4小节实验例程说明(中断方式): C. 另外强烈推荐用户将Cortex-M3内核的STM32F103和Cortex-M4内核的STM32F407,F429的NVIC优先级分组设置为4,即:NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);这样中断优先级的管理将非常方便。 D. 用户要在FreeRTOS多任务开启前就设置好优先级分组,一旦设置好切记不可再修改。 |
|
|
|
|
|
18.2 事件标志组API函数
使用如下11个函数可以实现FreeRTOS的事件标志组: xEventGroupCreate() xEventGroupCreateStatic() vEventGroupDelete() xEventGroupWaitBits() xEventGroupSetBits() xEventGroupSetBitsFromISR() xEventGroupClearBits() xEventGroupClearBitsFromISR() xEventGroupGetBits() xEventGroupGetBitsFromISR() xEventGroupSync() 关于这11个函数的讲解及其使用方法可以看FreeRTOS在线版手册: 这里我们重点的说以下4个函数: xEventGroupCreate() xEventGroupWaitBits() xEventGroupSetBits() xEventGroupSetBitsFromISR() 因为本章节配套的例子使用的是这4个函数。 |
|
|
|
|
|
18.2.1 函数xEventGroupCreate
函数原型: 复制代码 EventGroupHandle_t xEventGroupCreate( void ); 函数描述: 函数xEventGroupCreate用于创建事件标志组。 (1)返回值,如果创建成功,此函数返回事件标志组的句柄,如果FreeRTOSConfig.h文件中定义的heap空间不足会返回NULL #defineconfigTOTAL_HEAP_SIZE ( ( size_t ) (17 * 1024 ) ) 使用举例: 复制代码 static EventGroupHandle_t xCreatedEventGroup = NULL; /* ********************************************************************************************************* * 函 数 名: AppObjCreate * 功能说明: 创建任务通信机制 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ static void AppObjCreate (void) { /* 创建事件标志组 */ xCreatedEventGroup = xEventGroupCreate(); if(xCreatedEventGroup == NULL) { /* 没有创建成功,用户可以在这里加入创建失败的处理机制 */ } } |
|
|
|
|
|
18.2.3 函数xEventGroupSetBitsFromISR
函数原型: 复制代码 BaseType_t xEventGroupSetBitsFromISR( EventGroupHandle_t xEventGroup, /* 事件标志组句柄 */ const EventBits_t uxBitsToSet, /* 事件标志位设置 */ BaseType_t *pxHigherPriorityTaskWoken ); /* 高优先级任务是否被唤醒的状态保存 */ 函数描述: 函数xEventGroupSetBits用于设置指定的事件标志位为1。 (1)第1个参数是事件标志组句柄。 (2)第2个参数表示24个可设置的事件标志位,EventBits_t是定义的32位变量(详解18.1.2小节说明),低24位用于事件标志设置。变量uxBitsToSet的低24位的某个位设置为1,那么被设置的事件标志组的相应位就设置为1。变量uxBitsToSet设置为0的位对事件标志相应位没有影响。比如设置变量uxBitsToSet = 0x0003就表示将事件标志的位0和位1设置为1,其余位没有变化。 (3) 第3个参数用于保存是否有高优先级任务准备就绪。如果函数执行完毕后,此参数的数值是pdTRUE,说明有高优先级任务要执行,否则没有。 (4)返回值,如果消息成功发送给daemon任务(就是FreeRTOS的定时器任务)返回pdPASS,否则返回pdFAIL,另外daemon任务中的消息队列满了也会返回pdFAIL。 |
|
|
|
|
|
使用这个函数要注意以下问题:
1. 使用前一定要保证事件标志已经通过函数xEventGroupCreate创建了。同时要在FreeRTOSConfig.h文件中使能如下三个宏定义: #define INCLUDE_xEventGroupSetBitFromISR 1 #define configUSE_TIMERS 1 #define INCLUDE_xTimerPendFunctionCall 1 2. 函数xEventGroupSetBitsFromISR是用于中断服务程序中调用的,故不可以在任务代码中调用此函数,任务代码中使用的是xEventGroupSetBits。 3. 函数xEventGroupSetBitsFromISR对事件标志组的操作是不确定性操作,因为不知道当前有多少个任务在等待此事件标志。而FreeRTOS不允许在中断服务程序和临界段中执行不确定性操作。为了不在中断服务程序中执行,就通过此函数给FreeRTOS的daemon任务(就是FreeRTOS的定时器任务)发送消息,在daemon任务中执行事件标志的置位操作。同时也为了不在临界段中执行此不确定操作,将临界段改成由调度锁来完成。这样不确定性操作在中断服务程序和临界段中执行的问题就都得到解决了。 4. 由于函数xEventGroupSetBitsFromISR对事件标志的置位操作是在daemon任务里面执行的,如果想让置位操作立即生效,即让等此事件标志的任务能够得到及时执行,需要设置daemon任务的优先级高于使用此事件标志组的所有其它任务。 5. 通过下面的使用举例重点一下函数xEventGroupSetBitsFromISR第三个参数的规范用法,初学者务必要注意。 使用举例: 复制代码 #define BIT_0 (1 << 0) #define BIT_1 (1 << 1) #define BIT_ALL (BIT_0 | BIT_1) static EventGroupHandle_t xCreatedEventGroup = NULL; /* ********************************************************************************************************* * 函 数 名: TIM2_IRQHandler * 功能说明: 定时器中断。 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ static void TIM2_IRQHandler(void) { BaseType_t xResult; BaseType_t xHigherPriorityTaskWoken = pdFALSE; /* 中断消息处理,此处省略 */ …… /* 向任务vTaskMsgPro发送事件标志 */ xResult = xEventGroupSetBitsFromISR(xCreatedEventGroup, /* 事件标志组句柄 */ BIT_0 , /* 设置bit0 */ &xHigherPriorityTaskWoken ); /* 消息被成功发出 */ if( xResult != pdFAIL ) { /* 如果xHigherPriorityTaskWoken = pdTRUE,那么退出中断后切到当前最高优先级任务执行 */ portYIELD_FROM_ISR(xHigherPriorityTaskWoken); } } |
|
|
|
|
|
18.2.4 函数xEventGroupWaitBits
函数原型: 复制代码 EventBits_t xEventGroupWaitBits( const EventGroupHandle_t xEventGroup, /* 事件标志组句柄 */ const EventBits_t uxBitsToWaitFor, /* 等待被设置的事件标志位 */ const BaseType_t xClearOnExit, /* 选择是否清零被置位的事件标志位 */ const BaseType_t xWaitForAllBits, /* 选择是否等待所有标志位都被设置 */ TickType_t xTicksToWait ); /* 设置等待时间 */ 函数描述: 函数xEventGroupWaitBits等待事件标志被设置。 1、第1个参数是事件标志组句柄。 2、第2个参数表示等待24个事件标志位中的指定标志,EventBits_t是定义的32位变量(详解18.1.2小节说明),低24位用于事件标志设置。比如设置变量uxBitsToWaitFor = 0x0003就表示等待事件标志的位0和位1设置为1。此参数切不可设置为0。 3、第3个参数选择是否清除已经被置位的事件标志,如果这个参数设置为pdTRUE,且函数xEventGroupWaitBits在参数xTicksToWait设置的溢出时间内返回,那么相应被设置的事件标志位会被清零。如果这个参数设置为pdFALSE,对已经被设置的事件标志位没有影响。 4、第4个参数选择是否等待所有的标志位都被设置,如果这个参数设置为pdTRUE,要等待第2个参数uxBitsToWaitFor所指定的标志位全部被置1,函数才可以返回。当然,超出了在参数xTicksToWait设置的溢出时间也是会返回的。如果这个参数设置为pdFALSE,第2个参数uxBitsToWaitFor所指定的任何标志位被置1,函数都会返回,超出溢出时间也会返回。 5、第5个参数设置等待时间,单位时钟节拍周期。如果设置为 portMAX_DELAY,表示永久等待。 6、返回值,由于设置的时间超时或者指定的事件标志位被置1,导致函数退出时返回的事件标志组数值。 |
|
|
|
|
|
使用这个函数要注意以下问题:
1. 此函数切不可在中断服务程序中调用。 2. 这里再着重说明下这个函数的返回值,通过返回值用户可以检测是哪个事件标志位被置1了。 (1)如果由于设置的等待时间超时,函数的返回值可会有部分事件标志位被置1。 (2)如果由于指定的事件标志位被置1而返回,并且设置了这个函数的参数xClearOnExit为pdTRUE,那么此函数的返回值是清零前的事件标志组数值。 另外,调用此函数的任务在离开阻塞状态到退出函数xEventGroupWaitBits之间这段时间,如果一个高优先级的任务抢占执行了,并且修改了事件标志位,那么此函数的返回值会跟当前的事件标志组数值不同。 使用举例: 复制代码 #define BIT_0 (1 << 0) #define BIT_1 (1 << 1) #define BIT_ALL (BIT_0 | BIT_1) static EventGroupHandle_t xCreatedEventGroup = NULL; /* ********************************************************************************************************* * 函 数 名: vTaskMsgPro * 功能说明: 消息处理,使用函数xEventGroupWaitBits接收任务vTaskTaskUserIF发送的事件标志 * 形 参: pvParameters 是在创建该任务时传递的形参 * 返 回 值: 无 * 优 先 级: 3 ********************************************************************************************************* */ static void vTaskMsgPro(void *pvParameters) { EventBits_t uxBits; const TickType_t xTicksToWait = 100 / portTICK_PERIOD_MS; /* 最大延迟100ms */ while(1) { /* 等K2按键按下设置bit0和K3按键按下设置bit1 */ uxBits = xEventGroupWaitBits(xCreatedEventGroup, /* 事件标志组句柄 */ BIT_ALL, /* 等待bit0和bit1被设置 */ pdTRUE, /* 退出前bit0和bit1被清除,这里是bit0和bit1 都被设置才表示“退出”*/ pdTRUE, /* 设置为pdTRUE表示等待bit1和bit0都被设置*/ xTicksToWait); /* 等待延迟时间 */ if((uxBits & BIT_ALL) == BIT_ALL) { /* 接收到bit1和bit0都被设置的消息 */ printf("接收到bit0和bit1都被设置的消息rn"); } else { /* 超时,另外注意仅接收到一个按键按下的消息时,变量uxBits的相应bit也是被设置的 */ bsp_LedToggle(3); } } } |
|
|
|
|
|
18.3 实验例程说明(任务间通信)
18.3.1 STM32F103开发板实验 配套例子: V4-312_FreeRTOS实验_事件标志组 实验目的: 1. 学习FreeRTOS的事件标志组。 实验内容: 1. K1按键按下,串口打印任务执行情况(波特率115200,数据位8,奇偶校验位无,停止位1)。 2. K2键按下,直接发送事件标志给任务vTaskMsgPro,设置bit0。 3. K3键按下,直接发送事件标志给任务vTaskMsgPro,设置bit1。 4. 任务vTaskMsgPro只有接收到bit0和bit1都被设置了才执行串口打印消息。 5. 各个任务实现的功能如下: vTaskUserIF任务 :按键消息处理。 vTaskLED任务 :LED闪烁。 vTaskMsgPro任务 :消息处理,使用函数xEventGroupWaitBits接收任务vTaskTaskUserIF发送的事件标志。 vTaskStart任务 :启动任务,也是最高优先级任务,这里实现按键扫描。 FreeRTOS的配置: FreeRTOSConfig.h文件中的配置如下: 复制代码 /* Ensure stdint is only used by the compiler, and not the assembler. */ #if defined(__ICCARM__) || defined(__CC_ARM) || defined(__GNUC__) #include extern volatile uint32_t ulHighFrequencyTimerTicks; #endif #define configUSE_PREEMPTION 1 #define configUSE_IDLE_HOOK 0 #define configUSE_TICK_HOOK 0 #define configCPU_CLOCK_HZ ( ( unsigned long ) 72000000 ) #define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) #define configMAX_PRIORITIES ( 5 ) #define configMINIMAL_STACK_SIZE ( ( unsigned short ) 128 ) #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) ) #define configMAX_TASK_NAME_LEN ( 16 ) #define configUSE_TRACE_FACILITY 1 #define configUSE_16_BIT_TICKS 0 #define configIDLE_SHOULD_YIELD 1 /* Run time and task stats gathering related definitions. */ #define configGENERATE_RUN_TIME_STATS 1 #define configUSE_STATS_FORMATTING_FUNCTIONS 1 #define portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() (ulHighFrequencyTimerTicks = 0ul) #define portGET_RUN_TIME_COUNTER_VALUE() ulHighFrequencyTimerTicks //#define portALT_GET_RUN_TIME_COUNTER_VALUE 1 /* Co-routine definitions. */ #define configUSE_CO_ROUTINES 0 #define configMAX_CO_ROUTINE_PRIORITIES ( 2 ) /* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */ #define INCLUDE_vTaskPrioritySet 1 #define INCLUDE_uxTaskPriorityGet 1 #define INCLUDE_vTaskDelete 1 #define INCLUDE_vTaskCleanUpResources 0 #define INCLUDE_vTaskSuspend 1 #define INCLUDE_vTaskDelayUntil 1 #define INCLUDE_vTaskDelay 1 /* Cortex-M specific definitions. */ #ifdef __NVIC_PRIO_BITS /* __BVIC_PRIO_BITS will be specified when CMSIS is being used. */ #define configPRIO_BITS __NVIC_PRIO_BITS #else #define configPRIO_BITS 4 /* 15 priority levels */ #endif /* The lowest interrupt priority that can be used in a call to a "set priority" function. */ #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 0x0f /* The highest interrupt priority that can be used by any interrupt service routine that makes calls to interrupt safe FreeRTOS API functions. DO NOT CALL INTERRUPT SAFE FREERTOS API FUNCTIONS FROM ANY INTERRUPT THAT HAS A HIGHER PRIORITY THAN THIS! (higher priorities are lower numeric values. */ #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x01 |
|
|
|
|
|
几个重要选项说明:
1、#define configUSE_PREEMPTION 1 使能抢占式调度器 2、#define configCPU_CLOCK_HZ ( ( unsigned long ) 72000000 ) 系统主频72MHz。 3、#define configTICK_RATE_HZ ( ( TickType_t ) 1000 ) 系统时钟节拍1KHz,即1ms。 4、#define configMAX_PRIORITIES ( 5 ) 定义可供用户使用的最大优先级数,如果这个定义的是5,那么用户可以使用的优先级号是0,1,2,3,4,不包含5,对于这一点,初学者要特别的注意。 5、#define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) ) 定义堆大小,FreeRTOS内核,用户动态内存申请,任务栈等都需要用这个空间。 6、configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 0x01 定义受FreeRTOS管理的最高优先级中断。简单的说就是允许用户在这个中断服务程序里面调用FreeRTOS的API的最高优先级。为了进一步说明这个宏定义的的作用,解释如下: (1)使用CM内核的MCU,官方强烈建议将NVIC的优先级分组配置为全抢占式优先级,全部配置为抢占式优先级的好处就是方便管理。 (2)对于STM32来说,设置NVIC的优先级分组为4时,NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4)就是全部配置为抢占式优先级。又因为STM32的优先级设置仅使用CM内核8bit中的高4bit,即只能区分2^4 = 16种优先级。因此当优先级分组设置为4的时候可供用户选择抢占式优先级为0到15,共16个优先级,配置为0表示最高优先级,配置为15表示最低优先级,不存在子优先级。 (3)这里配置configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY为0x01表示用户可以在抢占式优先级为1到15的中断里面调用FreeRTOS的API函数,抢占式优先级为0的中断里面是不允许调用的。 |
|
|
|
|
|
FreeRTOS任务调试信息(按K1按键,串口打印):
上面截图中打印出来的任务状态字母B, R, D, S对应如下含义: #definetskBLOCKED_CHAR ( 'B' ) 任务阻塞 #definetskREADY_CHAR ( 'R' ) 任务就绪 #definetskDELETED_CHAR ( 'D' ) 任务删除 #definetskSUSPENDED_CHAR ( 'S' ) 任务挂起 |
|
|
|
|
|
使用事件标志组要包含的头文件:
使用FreeRTOS的事件标志组要包含头文件#include "event_groups.h",这个头文件在includes.h文件中进行了包含,具体如下: [url=]复制代码[/url]
程序设计: 任务栈大小分配: vTaskUserIF任务 :2048字节 vTaskLED任务 :2048字节 vTaskMsgPro任务 :2048字节 vTaskStart任务 :2048字节 任务栈空间是在任务创建的时候从FreeRTOSConfig.h文件中定义的heap空间中申请的 #defineconfigTOTAL_HEAP_SIZE ( ( size_t )( 17 * 1024 ) ) 系统栈大小分配: |
|
|
|
|
|
FreeROTS初始化:
复制代码 /* ********************************************************************************************************* * 函 数 名: main * 功能说明: 标准c程序入口。 * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ int main(void) { /* 在启动调度前,为了防止初始化STM32外设时有中断服务程序执行,这里禁止全局中断(除了NMI和HardFault)。 这样做的好处是: 1. 防止执行的中断服务程序中有FreeRTOS的API函数。 2. 保证系统正常启动,不受别的中断影响。 3. 关于是否关闭全局中断,大家根据自己的实际情况设置即可。 在移植文件port.c中的函数prvStartFirstTask中会重新开启全局中断。通过指令cpsie i开启,__set_PRIMASK(1) 和cpsie i是等效的。 */ __set_PRIMASK(1); /* 硬件初始化 */ bsp_Init(); /* 1. 初始化一个定时器中断,精度高于滴答定时器中断,这样才可以获得准确的系统信息 仅供调试目的,实际项 目中不要使用,因为这个功能比较影响系统实时性。 2. 为了正确获取FreeRTOS的调试信息,可以考虑将上面的关闭中断指令__set_PRIMASK(1); 注释掉。 */ vSetupSysInfoTest(); /* 创建任务 */ AppTaskCreate(); /* 创建任务通信机制 */ AppObjCreate(); /* 启动调度,开始执行任务 */ vTaskStartScheduler(); /* 如果系统正常启动是不会运行到这里的,运行到这里极有可能是用于定时器任务或者空闲任务的 heap空间不足造成创建失败,此要加大FreeRTOSConfig.h文件中定义的heap大小: #define configTOTAL_HEAP_SIZE ( ( size_t ) ( 17 * 1024 ) ) */ while(1); } |
|
|
|
|
|
硬件外设初始化
硬件外设的初始化是在bsp.c文件实现: [url=]复制代码[/url]
|
|
|
|
|
|
FreeRTOS任务创建:
复制代码 /* ********************************************************************************************************* * 函 数 名: AppTaskCreate * 功能说明: 创建应用任务 * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ static void AppTaskCreate (void) { xTaskCreate( vTaskTaskUserIF, /* 任务函数 */ "vTaskUserIF", /* 任务名 */ 512, /* 任务栈大小,单位word,也就是4字节 */ NULL, /* 任务参数 */ 1, /* 任务优先级*/ &xHandleTaskUserIF ); /* 任务句柄 */ xTaskCreate( vTaskLED, /* 任务函数 */ "vTaskLED", /* 任务名 */ 512, /* 任务栈大小,单位word,也就是4字节 */ NULL, /* 任务参数 */ 2, /* 任务优先级*/ &xHandleTaskLED ); /* 任务句柄 */ xTaskCreate( vTaskMsgPro, /* 任务函数 */ "vTaskMsgPro", /* 任务名 */ 512, /* 任务栈大小,单位word,也就是4字节 */ NULL, /* 任务参数 */ 3, /* 任务优先级*/ &xHandleTaskMsgPro ); /* 任务句柄 */ xTaskCreate( vTaskStart, /* 任务函数 */ "vTaskStart", /* 任务名 */ 512, /* 任务栈大小,单位word,也就是4字节 */ NULL, /* 任务参数 */ 4, /* 任务优先级*/ &xHandleTaskStart ); /* 任务句柄 */ } |
|
|
|
|
|
FreeRTOS事件标志组创建:
复制代码 /* ********************************************************************************************************* * 函 数 名: AppObjCreate * 功能说明: 创建任务通信机制 * 形 参: 无 * 返 回 值: 无 ********************************************************************************************************* */ static void AppObjCreate (void) { /* 创建事件标志组 */ xCreatedEventGroup = xEventGroupCreate(); if(xCreatedEventGroup == NULL) { /* 没有创建成功,用户可以在这里加入创建失败的处理机制 */ } } |
|
|
|
|
|
嵌入式学习-飞凌嵌入式ElfBoard ELF 1板卡-LCD显示图片编程示例之介绍mmap
238 浏览 0 评论
《DNESP32S3使用指南-IDF版_V1.6》第二章 常用的C语言知识点
629 浏览 0 评论
【RA-Eco-RA2E1-48PIN-V1.0开发板试用】(第三篇)ADC采集+PWM输出
552 浏览 0 评论
《DNK210使用指南 -CanMV版 V1.0》第四十五章 人脸识别实验
552 浏览 0 评论
1074 浏览 0 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
11763 浏览 31 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-22 21:02 , Processed in 0.966406 second(s), Total 101, Slave 83 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号