任务中的延时使用的是软件延时,即还是让CPU等待来达到延时的效果。使用RTOS的优势就是能充分发挥CPU的性能,永远不让它闲着。任务如果需要延时,也就不能再让CPU空等来实现延时的效果。RTOS中的延时叫作阻塞延时,即任务需要延时时,会放弃CPU的使用权,CPU可以去做其他的事情,当任务延时时间到,重新获取CPU使用权,任务继续运行,这样就充分地利用了CPU的资源,而不是空等
当任务需要延时而进入阻塞状态时,那CPU在做什么?如果没有其他任务可以运行,RTOS都会为CPU创建一个空闲任务,这个时候CPU就运行空闲任务。在FreeRTOS中,空闲任务是系统在启动调度器时创建的优先级最低的任务,空闲任务主体主要是做一些系统内存的清理工作。
xGetFreeStackSpace | 任务栈历史剩余最小值 |
#define Led2_PRIO 1 /* 任务优先级 */
#define Led2_STACK_SIZE 128 /* 任务堆栈大小*/
TaskHandle_t Led2_task_handler; /* 任务句柄 */
void Led2Task(void *argument); /* 任务函数声明 */
xTaskCreate((TaskFunction_t ) Led2Task, /* 任务函数 */
(char * ) "Led2", /* 任务名字 */
(configSTACK_DEPTH_TYPE ) Led2_STACK_SIZE, /* 堆栈大小 */
(void * ) NULL, /* 入口参数 */
(UBaseType_t ) Led2_PRIO, /* 任务优先级 */
(TaskHandle_t * ) &Led2_task_handler ); /* 任务句柄 */
void Led2Task(void *argument)
{
/* USER CODE BEGIN LedTask */
/* Infinite loop */
for(;;)
{
LED2_ON;
vTaskDelay(500);
LED2_OFF;
vTaskDelay(500);
}
/* USER CODE END LedTask */
}
? ? ? ?vTaskDelete(task1_handler); ? ? ? ? //填写任务句柄
// 删除任务
if(task1_handler!= NULL)
{
printf("删除start_task任务\r\n");
vTaskDelete(task1_handler); //填写任务句柄
task1_handler = ZERO;
}
//创建任务
if(Led2_task_handler == NULL)
{
xTaskCreate(Led2Task,"Led2",Led2_STACK_SIZE,
ZERO,Led2_PRIO,&Led2_task_handler );
}
vTaskDelete(null); Delete your own tasks
// 保护任务
taskENTER_CRITICAL(); /* 进入临界区 */
/* 被保护的代码 */
taskEXIT_CRITICAL(); /* 退出临界区 */
? ? ? ? 静态创建时,任务句柄作为返回值。
#define Led3_PRIO osPriorityLow /* 任务优先级 */
#define Led3_STACK_SIZE 128 /* 任务堆栈大小*/
TaskHandle_t Led3_task_handler; /* 任务句柄 */
StackType_t Led3_task_stack[Led3_STACK_SIZE]; /* 任务堆栈*/
StaticTask_t Led3_task_tcb; /* 任务控制块*/
void Led3Task(void *argument); /* 任务函数声明 */
Led3_task_handler = xTaskCreateStatic( (TaskFunction_t ) Led3Task, /* 任务函数 */
(char * ) "Led3", /* 任务名字 */
(uint32_t ) Led3_STACK_SIZE, /* 堆栈大小 */
(void * ) NULL, /* 入口参数 */
(UBaseType_t ) Led3_PRIO, /* 任务优先级* /
(StackType_t * ) Led3_task_stack, /* 任务堆栈 */
(StaticTask_t * ) &Led3_task_tcb ); /* 任务名字 */
????????vTaskSuspend(TaskHandle_t xTaskToSuspend)? ? //任务挂起? ——任务句柄
? ? ? ? ?vTaskResume(TaskHandle_t xTaskToResume)??? //任务恢复? ——任务句柄
????????xTaskResumeFromISR(TaskHandle_t xTaskToResume)?? //中断中任务恢复? ——任务句柄
vTaskSuspend(LedHandle);
vTaskResume(LedHandle);
? ? STM32 总共有16个优先级(0—15)? ? ?
portENABLE_INTERRUPTS(); //开启中断
portDISABLE_INTERRUPTS(); //关闭中断
什么是临界段:
????????临界段,用一句话概括就是一段在执行时不能被中断的代码段。在FreeRTOS中,临界段最常出现的地方就是对全局变量的操作。全局变量就像是一个靶子,谁都可以对其开枪,但是有一人开枪,其他人就不能开枪,否则就不知道是谁命中了靶子。
那么什么情况下临界段会被打断?一个是系统调度,还有一个就是外部中断。在FreeRTOS中,系统调度最终也是产生PendSV中断,在PendSV Handler中实现任务的切换,所以还是可以归结为中断。既然这样,FreeRTOS对临界段的保护最终还是回到对中断的开和关的控制。
作用:? 防止中断和任务调度的打断。
应用方面:
特点:
//开启和关闭任务调度器
vTaskSuspendAll() ;
{
… … /* 内容 */
}
xTaskResumeAll() ;
// 代码中使用,关闭所有中断
taskENTER_CRITICAL() ;
{
… … /* 临界区 */
}
taskEXIT_CRITICAL() ;
// 中断中使用,关闭所有中断
uint32_t save_status;
save_status = taskENTER_CRITICAL_FROM_ISR();
{
… … /* 临界区 */
}
taskEXIT_CRITICAL_FROM_ISR(save_status );