版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第9章FreeRTOS的任务和中断管理第9章
FreeRTOS的任务和中断管理【实践案例9-1】任务优先级与任务的调度【照猫画虎9-1】任务优先级与任务的调度【实践案例9-2】任务管理【照猫画虎9-2】任务管理【实践案例9-3】FreeRTOS中断管理【照猫画虎9-3】FreeRTOS中断管理
9.1.1轮询系统9.1.2前后台系统9.1.3多任务系统9.1多任务系统轮询系统是一种非常简单的软件结构,通常只适用于那些只需要顺序执行代码且不需要外部事件驱动就能实现的功能。在裸机系统中,一般先初始化好相关的硬件,然后让主程序通过无限死循环,顺序地执行指定的操作。9.1多任务系统轮询系统前后台系统是在轮询系统的基础上引入了中断技术,外部事件的响应在中断服务处理中完成,而事件的处理还是回到轮询系统中完成。在中断服务处理程序中实现外部事件的处理称为前台,而在主函数中的无限循环称为后台。在顺序执行后台程序的时候,如果有中断请求到来,则暂停后台程序的正常执行,转而执行中断服务程序。与轮询系统相比,前后台系统确保了事件不会丢失,再加上中断具有可嵌套的功能,可以大大地提高程序的实时响应能力。9.1多任务系统前后台系统在多任务系统中,根据功能将整个程序分割为若干个独立的、无限循环且不能返回的小程序,称为任务。任务(Task)是指计算机系统中正在执行或等待执行的一个独立的工作单元,是操作系统进行处理和资源分配的基本单位,可以是一个程序、一个进程或一个线程,取决于操作系统的设计和支持。多任务系统中的任务与中断一样,也具有优先级,优先级高的任务会被优先执行。当一个事件发生后,如果该事件对应的任务优先级足够高,就会立即得到响应。各任务是否能够得到响应和处理,以及多个任务响应和处理的顺序等,一般用专门的任务调度器实现。显然,任务调度器的功能类似于微机中的中断管理系统。9.1多任务系统多任务系统9.2任务的创建9.2.1任务与任务函数9.2.2FreeRTOS中的存储器管理9.2.3任务的创建9.2.1任务与任务函数在FreeRTOS中,每个任务都由三要素构成,即任务函数、任务栈和任务控制块。9.2任务的创建任务栈在多任务系统中,每个任务都是独立的,互不干扰的,所以要为每个任务都分配独立的栈空间。在FreeRTOS中,任务栈其实就是一个预先定义好的全局数组,数据类型为StackType_t(即uint32_t)。任务栈的大小默认为128字,即512字节,这也是FreeRTOS推荐的最小任务栈。9.2任务的创建任务控制块在多任务系统中,每个任务都需要一个任务控制块(Task-ControlBlock,TCB),系统对任务的全部操作(例如任务调度、任务的启动和停止运行等)都通过任务控制块实现。不同的任务有不同的任务控制块,其中存放有任务的所有信息,比如任务的栈指针、任务名称、任务所需的形参等。9.2任务的创建在task.c文件中,任务控制块定义为如下结构体类型:typedefstructtskTaskControlBlock{ volatileStackType_t *pxTopOfStack; //栈指针,指示任务栈位置 ListItem_t xStateListItem; //状态节点 ListItem_t xEventListItem; //事件节点 UBaseType_t uxPriority; //任务优先级 StackType_t *pxStack; //任务栈起始地址 char pcTaskName[configMAX_TASK_NAME_LEN]; 任务名称}tskTCB;9.2任务的创建任务函数在FreeRTOS中,任务是利用C语言函数实现的,实现任务规定功能的函数称为任务函数。任务函数与普通函数的主要区别在于其声明或者原型不同,任务函数的返回值必须为void,并且以指向void数据类型的指针作为参数。例如,如下语句voidATaskFunction(void*pvParameters);声明了一个任务函数ATaskFunction()。每个任务函数本身是一个程序,通常由一个死循环构成。FreeRTOS中的任务不能以任何方式从其实现函数中返回,也就是函数中不能有return语句,并且不能执行到函数体结束。如果不再需要执行一个任务,应该在程序中的合适位置用专门的语句将任务删除。
9.2任务的创建任务函数在FreeRTOS中,任务是利用C语言函数实现的,实现任务规定功能的函数称为任务函数。任务函数与普通函数的主要区别在于其声明或者原型不同,任务函数的返回值必须为void,并且以指向void数据类型的指针作为参数。例如,如下语句voidATaskFunction(void*pvParameters);声明了一个任务函数ATaskFunction()。每个任务函数本身是一个程序,通常由一个死循环构成。FreeRTOS中的任务不能以任何方式从其实现函数中返回,也就是函数中不能有return语句,并且不能执行到函数体结束。如果不再需要执行一个任务,应该在程序中的合适位置用专门的语句将任务删除。
9.2.2FreeRTOS中的存储器管理
在FreeRTOS中,任务的任务栈、任务控制块和任务函数都将分别占据一定的存储空间,创建任务也就是为各任务分配存储空间。采用不同的存储器(内存)管理方案,为任务进行存储分配的方法也各不相同。9.2任务的创建堆和栈FreeRTOS中的堆和栈是系统资源管理的关键。堆(Heap)用于动态内存分配,满足程序运行时需求;栈(Stack)则为函数调用提供临时存储空间。在应用程序中,应该合理管理堆和栈,确保系统稳定运行,避免资源泄露和溢出。9.2任务的创建堆和栈的区别9.2任务的创建静态和动态存储器分配在FreeRTOS中,可以采用静态或动态管理方案为任务进行存储器分配。静态存储器分配是在程序员编译程序时分配内存,动态存储器分配是程序员执行程序时分配内存。通过静态分配分配的内存在整个程序从编译到执行过程中都保持静态。由于内存已在编译时分配,因此减少了程序运行的时间,提高了运行速度。在动态内存分配中,不需要事先知道程序需要多少空间。通过动态分配的内存可以在程序执行期间随时分配和取消分配。由于这种方法根据程序的需要提供内存空间,因此内存使用更为高效。但是,由于内存是在运行时分配的,因此程序的执行速度稍慢。9.2任务的创建FreeRTOS中的动态内存管理方案为了使FreeRTOS使用尽可能方便,从FreeRTOSV9.0.0开始,内核组件(任务和队列等)都采用动态分配技术。当一个内核组件被创建时,FreeRTOS为其分配所需的内存,一旦该组件被删除,其所占用的内存也将被释放。在普通的C语言中,利用malloc()和free()函数实现动态内存的分配和释放,而在FreeRTOS中,分别利用函数pvPortMalloc()和vPortFree()函数实现的内存分配和释放。在FreeRTOS的FreeRTOS/Source/portable
/MemMang文件夹中,提供了这两个函数的5个实现实例,分别定义在heap_1.c
~heap_5.c源文件中,称为FreeRTOS的动态内存管理方案。9.2任务的创建A为创建所有任务之前的堆,整个数组是空的;B为创建了一个任务后的堆;C为创建了3个任务后的堆分配情况。9.2任务的创建A为创建了3个任务后的内存分配,在堆的顶部有大量的空闲内存。B为删除了其中一个任务后的内存分配,原来分配给被删除任务的栈和任务控制块也成为空闲内存(FreeSpace)。C为再次创建了一个任务后的内存分配情况,此时空闲内存将分配给新创建任务的TCB和任务栈。9.2任务的创建在这种方案中,能够将邻近的空闲存储块合并,从而减少内存中的碎片。因此这种方案适用于需要重复分配和释放不同大小内存块的情况。9.2任务的创建内存管理的相关配置9.2任务的创建显示当前以及使用的堆的个数9.2.3任务的创建9.2任务的创建任务创建函数(tasks.c/task.h)TaskHandle_txTaskCreateStatic(TaskFunction_tpxTaskCode, //任务函数名称 constchar*const pcName, //任务名称 constuint32_tulStackDepth, //任务栈大小(字) void*const pvParameters, //任务函数参数 UBaseType_t uxPriority, //任务优先级 StackType_t*constpuxStackBuffer, //任务栈起始地址 StaticTask_t*constpxTaskBuffer); //任务控制块指针静态内存分配创建任务:9.2任务的创建例如:staticStackType_tAppTaskCreate_Stack[128]; //定义任务栈staticStaticTask_tAppTaskCreate_TCB; //定义任务控制块指针AppTaskCreate_Handle=xTaskCreateStatic((TaskFunction_t)AppTaskCreate, (constchar*)"AppTaskCreate", (uint32_t)128, (void*)NULL, (UBaseType_t)3, (StackType_t*)AppTaskCreate_Stack, (StaticTask_t*)&AppTaskCreate_TCB); 9.2任务的创建BaseType_txTaskCreate(TaskFunction_t pvTaskCode, //任务函数名称 constchar*constpcName, //任务名称
configSTACK_DEPTH_TYPEusStackDepth, //任务栈大小(字) void*pvParameters, //任务函数参数 UBaseType_tuxPriority, //任务优先级 TaskHandle_t*pxCreatedTask); //任务句柄动态内存分配创建任务:例如xTaskCreate(vTask1,"Task1",1000,NULL,1,NULL); xTaskCreate(vTask2,"Task2",1000,NULL,1,NULL);9.2任务的创建与静态分配内存的任务创建函数相比,动态分配内存的任务创建函数主要有以下特点:任务栈在任务创建的时候创建,不需要预先定义一个全局的静态栈空间和任务栈起始地址,也就是在入口参数中不需要给定参数pxTaskBuffer,内存按需分配,随用随取。
任务控制块是通过在该函数中创建任务时通过自动分配内存空间而创建的,因此不需要预先定义任务控制块空间和TCB指针。函数xTaskCreate()返回的是BaseType_t数据类型,而xTaskCreateStatic()函数返回的是指向任务控制块(TaskHandle_t类型)的指针。9.2任务的创建CMSIS接口函数(cmsis_os2.c)osThreadId_tosThreadNew(osThreadFunc_tfunc,void*argument, constosThreadAttr_t*attr);其中前两个参数func和argument直接作为调用xTaskCreate()和xTaskCreateStatic()函数时所需的任务函数名和任务函数参数,第3个参数attr用于设置任务栈和任务控制块等属性,是指向osThreadAttr_t结构体类型的指针。在CubeMX配置创建任务后,将调用如下函数实现任务的创建:9.2任务的创建例如,在下面的语句中:defaultTaskHandle=osThreadNew(StartDefaultTask,NULL,&defaultTask_attributes);假设其中第3个结构体参数赋值如下:constosThreadAttr_tdefaultTask_attributes={ .name="defaultTask", .stack_size=128*4, .priority=(osPriority_t)osPriorityNormal,};则指定创建的任务名为defaultTask,任务栈的大小为128字即512字节,任务的优先级为osPriorityNormal。此外,任务函数名为StartDefaultTask,任务函数没有参数。
9.3任务调度9.3.1任务的优先级与状态9.3.2基础时钟与时间片9.3.3任务调度【实践案例9-1】任务优先级与任务的调度9.3.1任务的优先级与状态
在FreeRTOS中,每个任务都有一个优先级。所有任务能够设置的优先级总数由宏configMAX_PRIORITIES进行定义,该宏常量定义在头文件FreeRTOSConfig.h中,默认取值为56。在FreeRTOS中,所有任务最多可以有256个优先级,并且优先级数值越低,优先级别越低。最低优先级数值为0,最高优先级数值为255。9.3任务调度在cmsis_os2.h中,将任务的优先级数值定义为枚举类型osPriority_t,枚举类型中的各成员名称将出现在CubeMX新建任务面板的Priority下拉列表中,通过该面板可以为指定任务设置期望的优先级。任务的优先级
typedefenum{ …… osPriorityLow =8, //优先级low osPriorityLow1 =8+1, //优先级low+1 …… osPriorityLow7 =8+7, //优先级low+7 …… osPriorityNormal =24, //优先级normal …… osPriorityHigh7 =40+7, //优先级high+7 ……}osPriority_t;9.3任务调度9.3任务调度任务的状态及其切换FreeRTOS中的每个任务都有多种运行状态。系统初始化完成后,创建的任务就可以在系统中竞争一定的资源,由任务调度器进行调度。在系统运行过程中,各任务都在运行状态和非运行状态之间不断切换,其中任何一个时刻只有一个任务处于运行态,其他任务都处于非运行态,而非运行态又包括就绪、阻塞和挂起状态,如图9-4所示。9.3任务调度处于就绪、运行和阻塞状态的任务都可以进入挂起状态。处于挂起状态的任务不参与调度器的调度。挂起后的状态不能自动退出挂起状态,需要在其他任务里调用专门的函数使其转为就绪状态。任务创建完成后自动进入就绪态,表明任务已准备就绪,随时可以运行,只等待调度器进行调度。当发生任务切换时,就绪列表中最高优先级的任务被执行,从而进入运行态。
有更高优先级任务创建或者恢复后,会发生任务调度。此时就绪列表中最高优先级任务抢占到CPU从而变为运行态,原先运行的任务由运行态变为就绪态,依然在就绪列表中,等待最高优先级的任务运行完毕继续运行原来的任务。
任务的状态转换规则9.3任务调度正在运行的任务发生阻塞(挂起、延时、读信号量等待)时,任务状态由运行态变成阻塞态,然后发生任务切换,运行就绪列表中当前最高优先级任务。阻塞的任务被恢复后(任务恢复、延时时间超时、读信号量超时或读到信号量等),会加入就绪列表,从而由阻塞态变成就绪态。如果其优先级高于正在运行任务的优先级,则会发生任务切换,再次由就绪态转为运行态。
处于任何状态的任务都可以通过调用专门的任务管理函数将其挂起,被挂起的任务得不到CPU的使用权,也不会参与调度。通过调用专门的任务管理函数可以恢复挂起的任务,使其重新进入就绪态。9.3.2基础时钟与时间片
默认情况下,HAL库的时和系统节拍由SysTick产生。当应用程序使用RTOS时,由于FreeRTOS可以完全控制SysTick的配置,并且大多数RTOS强制配置SysTick为最低优先级,因此一般将SysTick用作FreeRTOS的时基源,而用另外的硬件时基源(例如定时器)作为HAL库使用的时基源。在CubeMX中的引脚和配置视图中,选择组件列表面板中的SYS外设,然后在SYSModeandConfigurstion面板的TimebaseSource(时基源)下拉列表中选择某个通用定时器TIM1、TIM2,即可将其配置为HAL库时基源,如图9-5所示。9.3任务调度基础时钟9.3.2基础时钟与时间片
默认情况下,HAL库的时和系统节拍由SysTick产生。当应用程序使用RTOS时,由于FreeRTOS可以完全控制SysTick的配置,并且大多数RTOS强制配置SysTick为最低优先级,因此一般将SysTick用作FreeRTOS的时基源,而用另外的硬件时基源(例如定时器)作为HAL库使用的时基源。在CubeMX中的引脚和配置视图中,选择组件列表面板中的SYS外设,然后在SYSModeandConfigurstion面板的TimebaseSource(时基源)下拉列表中选择某个通用定时器TIM1、TIM2,即可将其配置为HAL库时基源,如图9-5所示。9.3任务调度基础时钟9.3.2基础时钟与时间片
默认情况下,HAL库的时和系统节拍由SysTick产生。当应用程序使用RTOS时,由于FreeRTOS可以完全控制SysTick的配置,并且大多数RTOS强制配置SysTick为最低优先级,因此一般将SysTick用作FreeRTOS的时基源,而用另外的硬件时基源(例如定时器)作为HAL库使用的时基源。在CubeMX中的引脚和配置视图中,选择组件列表面板中的SYS外设,然后在SYSModeandConfigurstion面板的TimebaseSource(时基源)下拉列表中选择某个通用定时器TIM1、TIM2,即可将其配置为HAL库时基源,如图9-5所示。9.3任务调度基础时钟9.3任务调度一旦将某个定时器用作HAL库的时基源,该定时器就不能再用作普通定时器实现其他定时功能。配置HAL时基源为某个定时器后,在工程代码的HAL_init()函数中将继续调用在stm32f4xx_hal_timebase_TIM.c文件中重写的HAL_InitTick()函数实现指定定时器的初始化配置,使其每隔1ms(即系统时基)发出一次更新事件中断。在main.c中,将由CubeMX自动创建该定时器的定时到中断回调函数,以产生HAL所需的时基节拍。SysTick每定时1ms仍然会发出中断请求,FreeRTOS将在SysTick的定时中断中进行任务状态的检查、任务调度申请等操作。9.3任务调度注意事项所谓时间片(TimeSlice)就是多个优先级相同的任务轮流占用CPU的时间。在相同的优先级中,每个任务按照固定顺序依次执行一个时间片的时间,然后切换到下一个任务。如果一个任务在时间片结束之前没有执行完,该任务将被挂起,任务的当前状态即上下文(Context)将被保留,并在下一个循环中重新获得时间片后继续执行上次没有执行完的代码。通过划分时间片,操作系统能够公平地分享处理器时间给多个任务,使得各任务能够以看似同时的方式进行处理,提高了系统的多任务并行处理和响应性能。在FreeRTOS中,最小的时间单位为节拍tick,即SysTick的中断周期,默认为1ms,这也就是FreeRTOS进行任务调度所采用的时间片。
9.3任务调度时间片在FreeRTOS中提供了一个专门的延时函数vTaskDelay(),用于延时一定节拍数,并使当前任务进入阻塞状态。该函数的原型声明如下:voidvTaskDelay(constTickType_txTicksToDelay);其中参数xTicksToDelay表示基础时钟的节拍数,一般通过调用宏函数pdMS_TO_TICKS()将以毫秒为单位的延时时间参数转换得到。9.3任务调度阻塞延时在cmsis_os2.c文件中,将函数vTaskDelay()进一步封装为CMSIS接口函数osDelay()。因此,在基于CubeMX生成的工程中,典型的用法如下:TickType_tticks=pdMS_TO_TICKS(1000);/*将1s转换为系统节拍数*/osDelay(ticks); /*延时1s*/利用函数vTaskDelay()和osDelay()实现的延时称为阻塞延时。在等待延时的过程,任务一直处于阻塞状态,任务调度器可以按照任务优先级进行正常的任务调度,CPU可以执行其他任务。如果其他的任务也处于阻塞状态,则CPU将运行空闲任务。当指定的延时到时,该任务被唤醒,重新进入就绪状态。9.3任务调度在FreeRTOS中也可以调用HAL库中的延时函数HAL_Delay()。用该函数实现延时,在延时的过程中整个CPU都将处于阻塞状态,其他所有的任务和代码都将暂停执行,在延时过程中也不能进行任务调度和切换。在多任务系统中,任务中所需的延时(例如控制LED以指定的时间间隔闪烁)一般用阻塞延时实现,而HAL_Delay()函数一般在主程序或者中断服务程序中使用。除了vTaskDelay()和osDelay()函数以外,FreeRTOS中还定义了另外两个函数,即osDelayUntil()和vTaskDelayUntil()函数。这两个函数实现的是绝对延时,即以任务进入阻塞状态之后再被唤醒的时刻为参考的延时,而前面两个函数实现的延时是以任务刚进入阻塞状态为参考时刻。与osDelay()函数一样,osDelayUntil()也只有一个参数ticks,但vTaskDelayUntil()函数有两个参数,其原型声明如下:voidvTaskDelayUntil(TickType_t*constpxPreviousWakeTime, constTickType_txTimeIncrement);其中两个参数分别表示任务唤醒时基础时钟的计数值(节拍)和所需延迟的节拍数。9.3任务调度函数vTaskDelayUntil()的典型用法举例如下:tcnt=xTaskGetTickCount(); //获取当前系统节拍值delay=(TickType_t)pdMS_TO_TICKS(1000)-tcnt; //求延时的绝对时间,并转换为节拍数
vTaskDelayUntil(&tcnt,delay); //延时
9.3任务调度如果直接调用osDelayUntil()函数,可以将上述3条语句替换为如下语句:TickType_tticks=pdMS_TO_TICKS(1000); //将1s转换为节拍数
osDelayUntil(ticks); //延时
9.3.3任务调度
启动任务调度器时,将自动创建一个空闲任务(IdleTask),其优先级为portPRIVILEGE_BIT。在task.h文件中该优先级宏定义为0,代表最低优先级。在FreeRTOS中,任何时候都需要有一个任务占用CPU,处于运行状态。如果用户创建的任务都没有进入运行状态,例如都处于阻塞或挂起状态,此时空闲任务将占用CPU。由于空闲任务的优先级最低,因此一旦有任务被调度进入运行状态,将立即使空闲任务挂起,运行任务就绪列表中当前优先级最高的任务。9.3任务调度空闲任务常用的任务调度算法FreeRTOS提供了两种任务调度算法,即抢占式调度和合作式调度算法。其中抢占式调度算法基于任务的优先级进行任务调度,高优先级的任务可以抢占低优先级任务的执行。对优先级相同的任务,抢占式调度算法可以进一步基于时间片进行调度。9.3任务调度
基于时间片的抢占式调度算法当使用时间片进行任务调度时,基础时钟的每次中断都将使系统进行一次任务的上下文切换(ContextSwitching)。在上下文切换过程中,具有较高优先级的就绪任务获得CPU的使用权。如果多个任务具有相同的优先级,这些任务将以时间片为单位,轮流获得CPU的使用权。9.3任务调度高优先级任务能够抢占CPU的使用权。如果没有任何任务运行,则空闲任务立即进入运行状态。如果有多个处于就绪状态的任务具有相同的优先级,这些任务将以时间片为单位,轮流获得CPU的使用权。9.3任务调度
不基于时间片的抢占式调度算法不使用时间片的调度算法只在有更高级别的任务进入就绪状态,或者运行状态的任务进入阻塞状态或挂起状态时才进行任务调度,因此上下文切换的频率比使用时间片时低,从而可降低CPU的负担,但是对于同优先级的任务可能会出现占用CPU时间相差很大的情况。任务调度器的启动任务调度器根据上述调度算法实现任务的调度和切换。在应用程序的main()函数中,通过调用osKernelInitialize()初始化调度器,在通过调用MX_FREERTOS_Init()函数对FreeRTOS进行初始化以后,即可调用osKernelStart()函数启动任务调度器。函数osKernelStart()的完整定义在cmsis_os2.c中,其中主要的操作是通过调用定义在tasks.c文件中的函数vTaskStartScheduler()启动任务调度器。在该函数中,首先采用静态或动态内存分配方案创建一个空闲任务,并启动第一个处于就绪状态的任务的运行。在运行过程中,各任务之间的切换和调度都完全在任务调度器的控制下进行。9.3任务调度9.3任务调度【实践案例9-1】任务优先级与任务的调度在开发板上,除了用PF6、PF7和PF8分别控制红色、绿色和蓝色LED的亮/灭以外,PC3引脚还连接了一个单独的蓝色LED。为便于观察,本案例要求创建两个任务,控制开发板上PF6连接的红色LED和PC3连接的蓝色LED分别以1s和2s的间隔闪烁。9.3任务调度在CubeMX中将默认创建的任务defaultTask修改为vTask1,另外添加一个任务vTask2。两个任务分别控制PF6和PC3引脚输出的高低电平,其优先级等按照图9-8进行配置。9.3任务调度9.3任务调度9.3任务调度特别注意到在上述两个任务函数中,vTask1的优先级高于vTask2。此外,两个任务函数中的闪烁延时分别调用osDelay()函数和HAL_Delay()函数实现。编译成功后下载到开发板,可以看到两个LED分别以1s和2s的间隔不断闪烁。由于在任务1中的延时是阻塞延时,因此在等待延时的过程中,任务1处于阻塞状态。此时,通过任务调度,使得任务2得以执行。由于任务2是利用HAL_Delay()函数实现延时,不会进入阻塞状态,因此即便其优先级低于任务1,在任务1进入阻塞状态时仍然可以得到调度执行,从而实现蓝色LED的闪烁。9.4任务和调度器管理函数9.4.1任务管理函数9.4.2调度器管理函数9.4.3CMSIS接口函数【实践案例9-2】任务管理9.4任务和调度器管理函数9.4任务和调度器管理函数9.4.1任务管理函数
删除任务时,被删除的任务将从所有就绪、阻塞、挂起状态和事件列表中删除,FreeRTOS自动释放在创建该任务时为其动态分配的内存,包括栈空间和任务控制块。对采用静态内存分配创建的任务,必须在删除该任务之前手工释放为其分配的内存。任务的删除9.4任务和调度器管理函数/*创建一个任务,将创建的任务句柄存储在DeleteHandle中*/TaskHandle_t
DeleteHandle;xTaskCreate(DeleteTask,"DeleteTask",STACK_SIZE,NULL,PRIORITY,&DeleteHandle); /*创建任务DeleteTask*/voidDeleteTask(void){ /*DeleteTask任务函数*/ …… /*…用户代码*/ vTaskDelete(NULL); /*在任务函数中删除DeleteTask任务本身*/}……vTaskDelete(DeleteHandle); /*在其他任务中删除DeleteTask任务*/9.4任务和调度器管理函数挂起任务是使任务进入挂起状态,但是为任务分配的内部资源都会保留下来,只是任务暂时不参与调度。当调用恢复函数的时候,整个任务立即从挂起态进入就绪态,并且参与任务的调度,如果该任务的优先级是当前就绪态优先级最高的任务,那么立即会按照挂起前的任务状态继续执行该任务。任务可以通过调用vTaskSuspend()函数可以将处于任何状态的任务挂起,被挂起的任务得不到CPU的使用权,也不会参与调度,它相对于调度器而言是不可见的,直到解除其挂起态。任务的挂起与恢复9.4任务和调度器管理函数9.4.2调度器管理函数
函数vTaskSuspendAll()将所有的任务都挂起,从而将任务调度器锁定。调度器被挂起后则不能进行上下文切换,但是中断还是使能的。当调度器被挂起的时候,如果有中断需要进行上下文切换,那么这个中断将会被挂起,直到调用xTaskResumeAll()函数使调度器恢复之后才响应这个中断。9.4任务和调度器管理函数9.4.3CMSIS接口函数
在CMSIS-RTOS接口文件cmsis_os2.c/.h中,将上述任务管理函数做了进一步封装,得到的CMSIS接口函数名称前缀都为osThread。例如,将任务的恢复和删除分别封装为如下2个函数:osStatus_tosThreadResume(osThreadId_tthread_id); //恢复任务osStatus_tosThreadTerminate(osThreadId_tthread_id); //终止和删除任务其中,参数thread_id为任务句柄,两个函数的返回值都是osStatus_t类型。如果操作成功,则返回0(osOK);否则返回值小于0,分别表示给定的任务句柄无效、任务处于无效状态、不能在中断服务程序中调用等。9.4任务和调度器管理函数在调度器管理函数中,将启动、挂起和恢复调度器的函数分别封装为如下3个接口函数:osStatus_tosKernelStart(void) //启动调度器int32_tosKernelLock(void) //挂起调度器int32_tosKernelUnlock(void) //恢复调度器【实践案例9-2】任务管理本案例要求利用开发板上的按键K1控制红色LED的闪烁。每按动一次按键,LED以20ms的间隔闪烁1s。根据上述要求,需要创建两个任务,任务K1_Task用于检测按键的按动和释放,任务LED_Task用于实现红色LED的闪烁。初始化时将任务LED_Task挂起。在K1_Task中,每检测到按键K1按动一次(按下再等待释放),恢复LED_Task到就绪任务列表中。如果设置LED_Task的优先级高于K1_Task,则LED_Task立即进入运行状态,控制LED开始闪烁。恢复LED_Task后,在K1_Task中延时1s再将其挂起,从而暂停LED闪烁。9.4任务和调度器管理函数在CubeMX中新建工程,配置系统时钟、GPIO(PF6为输出模式、PA0为输入模式),配置HAL时基源为TIM6。配置FreeRTOS为CMSIS_V2模式。在TasksandQueues面板中,将原来自动创建的默认任务修改为LED_Task(注意默认任务无法删除,但可以修改其属性),另外创建任务K1_Task,并设置两个任务的优先级,如图9-9所示。9.4任务和调度器管理函数9.4任务和调度器管理函数9.4任务和调度器管理函数一旦检测到K1按钮按下,则立即恢复任务LED_Task。由于其优先级高于任务K1_Task,因此通过调度立即执行该任务,使红色LED闪烁。延时1000ms后,再将任务LED_Task挂起,从而使LED停止闪烁。由于LED_Task挂起,使得低优先级的K1_Task任务得以执行,以便重复检测等待K1按钮是否按下。9.4任务和调度器管理函数9.5中断管理9.5.1中断管理的运作机制9.5.2中断的优先级9.5.3FreeRTOS中的两套API函数【实践案例9-3】FreeRTOS中断管理9.5中断管理FreeRTOS的运行要用到中断,作为FreeRTOS基础时钟的SysTick,每经过一个时间片会发出中断请求。此外,在一个应用系统中,可能也会用到其他外部中断。例如,利用按键中断控制任务的调度、任务的运行和挂起等;ADC转换结束后发出中断请求,并要求调度器启动相关任务对转换结果数据进行处理等。FreeRTOS中断管理的目的是:当MCU接收到中断时,在内核稳定运行的情况下能够快速响应中断。9.5中断管理中断使得CPU可以在事件发生时才给予处理,而不必让CPU连续不断地查询是否有相应的事件发生。在关闭中断期间,通常处理器会把新产生的中断挂起,当中断打开时立刻进行响应。当中断产生时,CPU将保存当前CPU状态信息、将CPU控制权转交给中断服务程序并开始执行,当中断处理函数执行完成时,恢复CPU状态信息,再返回到前一个程序执行点。
在FreeRTOS中,CPU一旦接收到中断,无论原来正在执行的任务优先级如何,都会打断当前任务的执行,并转而执行对应的中断服务和处理,其过程具体如图9-10所示。9.5.1中断管理的运作机制9.5中断管理9.5中断管理FreeRTOS中的中断管理规则在FreeRTOS中,所有中断的优先级高于任务,因此任务只有在没有中断的情况下才能得到执行。如果CPU正在处理某个中断,在执行中断处理的过程中,如果有更高优先级别的中断源触发中断,不同的处理器系统可能有不同的处理方式。例如,可以与裸机系统一样进行正常的中断嵌套处理,也可以挂起新的中断直到当前中断处理完毕后再予以响应。9.5中断管理启用FreeRTOS后,在CubeMX中的NVIC配置面板中自动将中断优先级分组配置为4bitforpre-emptionpriority0bitforsubpriority,即4位全部用于中断的抢占优先级,因此FreeRTOS中所有中断的抢占优先级为0~15。在抢占优先级中,数值越低优先级越高。此外,FreeRTOS可管理的中断最高和最低优先级分别由宏常量LIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY和LIBRARY_LOWEST_INTERRUPT_PRIORITY参数设置。在CubeMX中,这两个参数位于FreeRTOS配置面板的Configparameters选项卡中,默认值分别为15和5。9.5.2中断的优先级9.5中断管理按照上述默认设置,FreeR
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2026中国户外运动安全设备行业发展瓶颈与突破路径研究报告
- 医保源头作弊风险总结2026
- 2026中国养老服务行业市场全面分析及服务模式与行业发展趋势研究报告
- 2026汽车零部件制造业技术创新投资评估市场竞争格局优化研究
- 2026中国橡胶加工设备行业市场现状供需分析及投资评估规划分析研究报告
- 2026中国碳化硅纤维航空航天领域技术突破与商业化应用报告
- 2026期权市场投资发展趋势及融资策略研究报告
- 2026瑞典直升机生产行业市场发展趋势政策影响竞争格局投资规划报告
- 2026蚯蚓养殖产业发展现状分析及收益最大化研究
- 2026中国运动康复器械终端渠道变革与营销创新战略报告
- 2026年征兵政治考核面试题库及参考答案
- 2025年GPON 和 XG(S)-PON 技术白皮书
- (正式版)T∕GDSTD 023-2026 广东省自然资源资产配置方案编制指南
- 2026机动车检测站授权签字人试题库(含答案)
- GB/T 25085.5-2026道路车辆汽车电缆第5部分:交流600 V或直流900 V和交流1 000 V或直流1 500 V单芯铜导体电缆的尺寸和要求
- 养鹅场水资源管理方案
- 热工技术监督实施细则培训课件
- 2025年新疆医科大学第四附属医院(新疆维吾尔自治区中医医院)面向社会公开招聘事业单位工作人员110人备考题库完整答案详解
- 电伴热带热设计计算表(静态)
- 检验人员培训与考核制度
- 院感和无菌技术
评论
0/150
提交评论