如果我们想在执行某段代码时不被中断打断,此时需要进行临界区代码保护 。在临界区内关闭中断,临界区结束后开启中断。
需要注意的是临界区的进入和退出需要成对出现,如果进入两次,那么需要退出两次才可以成功开启中断。
注:本实验基于正点原子FreeRTOS教程的学习总结。
taskENTER_CRITICAL函数用来进入临界区。在任务中调用。
#define taskENTER_CRITICAL() portENTER_CRITICAL()
taskENTER_CRITICAL_FROM_ISR函数用来进入临界区,返回值为临界区状态。在FreeRTOS管理的中断中调用。
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
//例子:
uint_t status;
status = taskENTER_CRITICAL_FROM_ISR();
taskENTER_CRITICAL函数用来退出临界区。在任务中调用。
#define taskEXIT_CRITICAL() portEXIT_CRITICAL()
taskENTER_CRITICAL_FROM_ISR函数用来退出临界区,输入值为临界区状态。在FreeRTOS管理的中断中调用。
#define taskEXIT_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()
//例子:
taskEXIT_CRITICAL_FROM_ISR(status);
taskENTER_CRITICAL()函数进入临界区,关闭中断(任务不会切换)。
taskEXIT_CRITICAL()函数退出临界区,开启中断。
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区,关闭中断(任务不会切换)
//创建task1
xTaskCreate((TaskFunction_t )task1, /* 任务函数 */
(const char* )"task1", /* 任务名称 */
(uint16_t )TASK1_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )TASK1_PRIO, /* 任务优先级 */
(TaskHandle_t* )&Task1_Handler); /* 任务句柄 */
vTaskDelete(NULL);//删除start_task任务
taskEXIT_CRITICAL(); //推出临界区,开启中断
}
任务调度器的挂起与进入临界区不同,任务调度器的挂起主要防止任务间的资源争夺。任务调度器挂起后当前任务不能切换,相当于屏蔽PendSV标志,但是可以被中断打断;而进入临界区,任务不可以切换,中断不能打断。
vTaskSuspendAll函数用来任务调度器的挂起。在任务中调用。
void vTaskSuspendAll( void ) PRIVILEGED_FUNCTION;
xTaskResumeAll函数用来任务调度器的恢复,返回值表示是否需要进行任务切换,pdTRUE表示需要任务切换,pdFAULT表示不需要任务切换。在任务中调用。
BaseType_t xTaskResumeAll( void ) PRIVILEGED_FUNCTION;
vTaskSuspendAll()函数挂起任务调度器(任务不会切换)。
xTaskResumeAll()函数恢复任务调度器(任务可以切换)。
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区,关闭中断(任务不会切换)
//创建task1
xTaskCreate((TaskFunction_t )task1, /* 任务函数 */
(const char* )"task1", /* 任务名称 */
(uint16_t )TASK1_STK_SIZE, /* 任务堆栈大小 */
(void* )NULL, /* 传入给任务函数的参数 */
(UBaseType_t )TASK1_PRIO, /* 任务优先级 */
(TaskHandle_t* )&Task1_Handler); /* 任务句柄 */
vTaskDelete(NULL);//删除start_task任务
taskEXIT_CRITICAL(); //推出临界区,开启中断
}