FreeRTOS 任务挂起和恢复API函数使用
挂起的作用就是当我们需要暂停某任务时候,等过一段时间在运行,这个时候要是使用删除和重建的方法就会当时任务进行时候的变量保存的值。当需要将这个任务停止运行一段时间的将这个任务挂起,当重新进行运行这个任务就恢复运行。
vTaskSuspend()//挂起一个任务
vTaskResume()//恢复一个任务的运行
xTaskResumeFromISR()//中断服务函数中恢复一个任务的进行
一旦将某个任务设置为挂起态,进入挂起态的任务永远都不会进入运行态。除非对当前这个任务进行解挂,
1
void vTaskSuspend( TaskHandle_t xTaskToSuspend)
xTaskToSuspend: 要挂起的任务的任务句柄,创建任务的时候会为每个任务分配一个任务句柄。如果使用函数 xTaskCreate()创建任务的话那么函数的参数,pxCreatedTask
就是此任务的任务句柄,如果使用函数xTaskCreateStatic()
创建任务的话那么函数的返回值就是此任务的任务句柄。也可以通过函数 xTaskGetHandle()
来根据任务名字来获取某个任务的任务句柄。注意!如果参数为NULL 的话表示挂起任务自己。
2
vTaskResume()//恢复一个任务的运行,xTaskToResume: 要恢复的任务的任务句柄。
3
BaseType_t xTaskResumeFromISR( TaskHandle_t xTaskToResume)
xTaskToResume: 要恢复的任务的任务句柄。返回值:pdTRUE:恢复运行的任务的任务优先级等于或者高于正在运行的任务(被中断打断的任务),这意味着在退出中断服务函数以后必须进行一次上下文切换。pdFALSE:恢复运行的任务的任务优先级低于当前正在运行的任务(被中断打断的任务),这意味着在退出中断服务函数的以后不需要进行上下文切换。
换句话就是当中断恢复挂起的优先级等于高于的时候,就会切换另一个任务,否则不会切换这个任务。想象一下,你在做一件非常重要的事情(比如做饭),这时候有人敲门(这就像是一个中断)。根据敲门的人是谁(中断的优先级),你会决定是否暂停做饭去开门(中断服务),还是让他们等一会儿。
pdTRUE 的情况:
如果敲门的人是你的好朋友,而且你已经约好了(这意味着“中断”很重要,优先级高或等同于你正在做的事情),你会选择停下手中的事情(做饭),去开门(处理中断)。在开完门后,你可能会决定先陪陪朋友,不立即回去做饭(这就是所谓的“上下文切换”,从一个任务切换到另一个)。
pdFALSE 的情况:
相反,如果敲门的是一个推销员(这意味着“中断”不太重要,优先级较低),你可能会决定让他等一下,继续做饭(即使你知道门外有人)。这个时候,你没有放下手中的事情去开门,也就没有发生“上下文切换”。
在实时操作系统(RTOS)中,任务(比如做饭)有不同的优先级,中断也是如此。系统需要决定在中断发生时是否暂停当前任务去处理中断,以及处理完中断后是否回到原来的任务或者转去做另一个更重要的任务。这个决定基于任务和中断的优先级:
- 如果中断很重要(优先级高或相等),系统会处理中断,并可能转去做另一个任务(pdTRUE)。
- 如果中断不那么重要(优先级低),系统会忽略它,继续当前的任务(pdFALSE)。
接下来我们编写程序来使用挂起以及恢复函数:
我们将创建三个任务:
void LED0_task(void *pvParameters)
{
u16 task1num = 0;
while(1)
{
printf("task1num=%d\r\n",++task1num);
LED0 = ~LED0;
vTaskDelay(500);
}
}
void LED1_task(void *pvParameters)
{
u16 task2num = 0;
while(1)
{
printf("task2num=%d\r\n",++task2num);
LED1 = ~LED1;
vTaskDelay(500);
}
}
void KEY_task(void *pvParameters)
{
u8 key = 0;
while(1)
{
key = KEY_Scan(0);
if(key == KEY0_PRES)
{
printf("在任务中挂起任务1\r\n");
vTaskSuspend(LED0Task_Handler);
}
if(key == KEY1_PRES)
{
printf("在任务中恢复任务1\r\n");
vTaskResume(LED0Task_Handler);
}
vTaskDelay(10);
}
具体来说就是这三个,同时我们在按键任务设置了按键0按下在任务中挂起任务1也就是LED0任务,接下来我们使用中断恢复任务1,具体代码如下:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
BaseType_t xYieldRequired;
delay_ms(100); //消抖
switch(GPIO_Pin)
{
case GPIO_PIN_0:
if(WK_UP==1)
{
xYieldRequired = xTaskResumeFromISR(LED0Task_Handler);
printf("在中断中恢复任务1\r\n");
}
if(xYieldRequired == pdTRUE)
{
portYIELD_FROM_ISR(xYieldRequired);
}
break;
}
}
portYIELD_FROM_ISR(xYieldRequired)
是在许多实时操作系统(RTOS)中用于从中断服务例程(ISR)触发任务上下文切换的函数。
但是我们在串口中会发现出现了错误,在port.c769行中,我们进入到这个函数,可以定位这个代码:
该报错意思是当前中断的优先级大于系统能够管理的优先级。打开FreeRTOSConfig.h,可以找到下面管理的优先级的最大值和最小值。
在FreeRTOS内有一个configMAX_SYSCALL_INTERRUPT_PRIORITY的宏,它是配置FreeRTOS能够管理中断的最大优先级,FreeRTOS内中断优先级分组只能全部配置成抢占优先级,没有子优先级,FreeRTOS也没有处理子优先级的代码。在FreeRTOS内只有大于configMAX_SYSCALL_INTERRUPT_PRIORITY才能调用FreeRTOS API(中断优先级很低),小于configMAX_SYSCALL_INTERRUPT_PRIORITY不能调用FreeRTOS的API(中断优先级很高),如果调用了就会出现上述问题。
所以这里设置分组四,也就是4位全部用抢占优先级,0位响应优先级。
并且这里也要更改。然后编译下载烧录进去。发现这个时候就能够正常运行。串口接受的信息没有报错。