Article directory
1. Task suspend and resume API functions
In the project, we sometimes encounter certain tasks that need to be suspended for a period of time and then rerun after a period of time. Task suspension and resumption fulfills this need. When a task needs to be suspended for a period of time, it can be suspended. When you need to restart, just restore it. . The task suspension and recovery API functions of FreeRTOS are as follows
1.1 vTaskSuspend() function
The function of this function is to set a task to the pending state. Once a task enters the suspended state, it will never enter the running state. Unless the task recovery function vTaskResume() or xTaskResumeFromISR() is called. The task suspend function has the following input parameters
- xTaskToSuspend
The task handle of the task to suspend.如果需要挂起任务自身,该参数写NULL。
The task suspend function has no return value.
1.2 vTaskResume() function
The function of this function is to restore a task from the suspended state to the ready state. The task recovery function has the following input parameters
- The task handle of the task that xTaskToResume
needs to resume.
The task recovery function also has no return value.
1.3 xTaskResumeFromISR() function
The function of this function is to resume a task in the interrupt service function. The function has the following input parameters
- xTaskToResume
The task handle of the task to resume.
This function has the following return value
The task priority of the task resumed by pdTRUE is equal to or higher than that of the running task (the task interrupted by the interrupt), which means that a context switch must be performed after exiting the interrupt service function .- pdFALSE
The task priority of the resumed task is lower than that of the currently running task (the task interrupted by the interrupt), which means that no context switch is required after exiting the interrupt service function.
2. Task suspend and resume
2.1 Task 1 suspends and unsuspends task 2
For task creation, see the previous article, task creation and deletion. Modify task 1 directly here. Task 1 is modified to suspend task 2 after running task 1 10 times. After running 10 more times, unhook task 2. The task 1 function is as follows
void taks1_task (void *pxCreatedTask)
{
u8 task1Cunt = 0; // 任务1运行次数计数变量
while (1)
{
task1Cunt = task1Cunt + 1; // task1运行次数加1
Med_Led_StateReverse(LED0); // LED0状态取反
vTaskDelay(500); // 延时500ms
// 运行5次后
if (task1Cunt == 10)
{
// 挂起任务2
vTaskSuspend(TASK2Task_Handler);
}
if (task1Cunt == 20)
{
// 解挂任务2
vTaskResume(TASK2Task_Handler);
}
}
}
2.2 Unsuspend task 1 during interruption
At the beginning, I tried to suspend and unsuspend task 1 in the external interrupt, and found that when task 1 was suspended, the program was abnormal. After querying, I found out, 在中断中不能使用挂起函数。
so I adjusted it a bit. After task 2 runs 5 times, task 1 is suspended. Unhook task 1 through external interrupt.
Pay attention when unsuspending the task during the interrupt, you need to judge the return value of the function xTaskResumeFromISR(). 如果函数xTaskResumeFromISR()返回值为pdTRUE,那么说明要恢复的这个任务的任务优先级等于或者高于正在运行的任务(被中断打断的任务),所以在退出中断的时候一定要进行上下文切换
.
The external interrupt program configuration is as follows
/*
*==============================================================================
*函数名称:Exit_Init
*函数功能:初始化外部中断
*输入参数:无
*返回值:无
*备 注:无
*==============================================================================
*/
void Exit_Init (void)
{
NVIC_InitTypeDef NVIC_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); // 开启AFIO时钟
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //选择GPIO管脚用作外部中断线路
//EXTI0 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; //EXTI0中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=6; //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
EXTI_InitStructure.EXTI_Line=EXTI_Line0; // EXIT0
EXTI_InitStructure.EXTI_Mode=EXTI_Mode_Interrupt; // 中断
EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising; // 上升沿触发
EXTI_InitStructure.EXTI_LineCmd=ENABLE; // 使能
EXTI_Init(&EXTI_InitStructure);
}
The interrupt service function of the external interrupt is as follows
/*
*==============================================================================
*函数名称:EXTI0_IRQHandler
*函数功能:外部中断0中断服务函数
*输入参数:无
*返回值:无
*备 注:无
*==============================================================================
*/
// 任务1的任务句柄
extern TaskHandle_t TASK1Task_Handler;
void EXTI0_IRQHandler(void)
{
BaseType_t YieldRequired;
// 如果EXIT0中断标志位被置1
if(EXTI_GetITStatus (EXTI_Line0)==1)
{
YieldRequired = xTaskResumeFromISR(TASK1Task_Handler); // 恢复任务1
if(YieldRequired == pdTRUE)
{
// 执行一次任务调度
portYIELD_FROM_ISR(YieldRequired);
}
}
EXTI_ClearITPendingBit (EXTI_Line0); // 清除中断标志位
}
3. Supplementary content
3.1 FreeRTOS data types
In the portmacro.h header file, two data types are defined
- TickType_t
FreeRTOS interrupt count value type, which can be 16 bits or 32 bits. For 32-bit CPUs, TickType_t is preferably 32 bits. - BaseType_t
enables the CPU to run the most efficient data type. For 32-bit CPUs, BaseType_t is uint32_t. A 16-bit CPU is uint16_t, and an 8-bit CPU is uint8_t.
3.2 Interrupt priority grouping
Priority grouping: The interrupt controller (NVIC) allows the bits defining the priority of each interrupt to be split into priority bits defining the interrupt and sub-priority bits defining the interrupt. For simplicity, all bits must be defined as preemptive priority bits . If this is not the case (if some bits indicate subpriority), the assertion below will fail.
简单来说,就是在设置优先级分组时,需要将全部的位都设置为抢占优先级。否则会导致程序异常。
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4); // 设置系统中断优先级分组4
3.3 Error problem
When compiling, I found the following error message
该错误是因为“task.h”必须出现在“FreeRTOS.h”下面。