FreeRTOS学习随笔(2),FreeRTOS中断管理

  • Post author:
  • Post category:其他




宏configMAX_SYSCALL_INTERRUPT_PRIORITY

上次在讲临界区的时候提到了这个宏,下面来解释一下。

低于此优先级的中断可以安全调用FreeRTOS的API函数,高于此优先级的中断是FreeRTOS不能禁止的,中断服务函数也不能调用FreeRTOS的API函数!

如以STM32为例,设置NVIC优先级分组为4,即有16个抢占优先级,0最高,15最低,设置

configMAX_SYSCALL_INTERRUPT_PRIORITY

为5,则:


优先级0-4不会被FreeRTOS禁止,中断不可以调用FreeRTOS的API函数。



优先级5-15可以调用以FROM_ISR结尾的API函数,并且它们可以中断嵌套。


下面通过实验来验证一下。



FreeRTOS中断测试实验



实验目的

验证上述的

configMAX_SYSCALL_INTERRUPT_PRIORITY

作用。使用两个定时器,一个优先级为4,一个优先级为5,两个定时器每隔1s通过串口输入一段字符串。然后在某个任务中关闭中断一段时间,查看两个定时器的输出情况。



实验设计

设计两个任务

startTask()



interruptTask()

,功能如下:


startTask()

:创建另外一个任务。


interruptTask()

:中断测试任务,任务中会调用关闭中断函数

portDISABLE_INTERRUPTS()

来关闭中断一段时间。

TIM3和TIM5配置不再赘述,注意抢占优先级的设置,TIM3为4,TIM5为5(因为我们设置的configMAX_SYSCALL_INTERRUPT_PRIORITY为5)。

main函数代码如下:

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "timer.h"
#include "FreeRTOS.h"
#include "task.h"
/*********************任务设置区*********************/
#define startTask_STK_SIZE	120				//开始任务的堆栈大小,实际大小为120*4
#define startTask_PRIO	1							//空闲任务的优先级为0,一般不用0,数字越大,优先级越高	
void startTask(void *pvParameters);		//任务函数
TaskHandle_t startTask_Handler;				//任务句柄,别的任务通过句柄调用该任务

#define intrruptTask_STK_SIZE	256				//开始任务的堆栈大小,实际大小为120*4
#define intrruptTask_PRIO	2							//空闲任务的优先级为0,一般不用0,数字越大,优先级越高	
void intrruptTask(void *pvParameters);		//任务函数
TaskHandle_t intrruptTask_Handler;				//任务句柄,别的任务通过句柄调用该任务
/***************************************************/

int main(void){
/*变量声明区*/
	u16 arr = 9999;		//计数值10000,为1s
	u16 psc = 7199;		//72MHz时钟,分频系数7200,计数频率为10kHz
/*资源初始化*/
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	delay_init();
	uart_init(115200);
	LED_Init();
	TIM3_Int_Init(arr,psc);		//设置计时1s
	TIM5_Int_Init(arr,psc);
/*任务调度区*/
	xTaskCreate(
		(TaskFunction_t ) startTask,
		(const char *		) "startTask",					//任务名
		(uint16_t 			) startTask_STK_SIZE,		//任务堆栈大小
		(void * 		 		) NULL,							//任务输入参数
		(UBaseType_t		) startTask_PRIO,				//任务优先级
		(TaskHandle_t * ) &startTask_Handler 		//任务句柄
	);
	vTaskStartScheduler();			//启用任务调度
}

/*startTask*/
void startTask(void *pvParameters){
	taskENTER_CRITICAL();
	xTaskCreate(
		(TaskFunction_t ) intrruptTask,
		(const char *		) "intrruptTask",					//任务名
		(uint16_t 			) intrruptTask_STK_SIZE,		//任务堆栈大小
		(void * 		 		) NULL,							//任务输入参数
		(UBaseType_t		) intrruptTask_PRIO,				//任务优先级
		(TaskHandle_t * ) &intrruptTask_Handler 		//任务句柄
	);
	vTaskDelete(startTask_Handler);
	taskEXIT_CRITICAL();
}

/*intrruptTask*/
void intrruptTask(void *pvParameters){
	static u32 cnt = 0;
	while(1){
		cnt += 1;
		if(cnt == 5){
			printf("关闭中断\r\n");
			portDISABLE_INTERRUPTS();		
			delay_xms(5000);		//注意这里!不能调用vTaskDelay()!!!!
			printf("开启中断\r\n");
			portENABLE_INTERRUPTS();
		}
		vTaskDelay(1000);
	}
}

值得注意的是:在

intrruptTask()

中,关闭中断和开启中断之间的延时不能调用vTaskDelay()!


关闭中断和开启中断之间的延时不能调用vTaskDelay()!

关闭中断和开启中断之间的延时不能调用vTaskDelay()!

关闭中断和开启中断之间的延时不能调用vTaskDelay()!


因为

vTaskDelay()

会引起任务调度,可能会调度到含有开启中断的任务,所以这里不能使用FreeRTOS自带的

vTaskDelay()

,应使用内核的延时函数。

参考:

正点原子,手把手教你学FreeRTOS



版权声明:本文为weixin_46961467原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。