FreeRTOS断言“freertos\portable\rvds\arm_cm3\port.c,244“的解决方法

FreeRTOS断言"freertos\portable\rvds\arm_cm3\port.c,244"的解决方法

这两天刚上手FreeRTOS,写程序的时候,中途编译烧录调试,代码很简单,我也感觉没啥问题,但是在串口中打印了断言freertos\portable\rvds\arm_cm3\port.c,244,检查代码多次未能解决问题,网上也只有一篇文章提到这个问题,最终我在正点原子的论坛上找到了答案。
代码的内容就是:
两个定时器中断TIM3和TIM5。TIM3优先级高于configMAX_SYSCALL_INTERRUPT_PRIORITY,即该中断不能被FreeRTOS的portDISABLE_INTERRUPTS()函数停止;TIM5优先级则低于configMAX_SYSCALL_INTERRUPT_PRIORITY,即它可以被停止。
每隔1s向串口打印信息,然后在任务中调用portDISABLE_INTERRUPTS()关闭中断,那么TIM3应该能继续输出,而TIM5则不能。

在代码中,建立了两个任务,一个是开始任务startTask(),一个是关中断的任务intrruptTask(),在开始任务中创建关中断的任务。


重点来了,我写到一半的时候,直接写了个intrruptTask()的空函数放那了,里面没有写死循环。这时烧录上去,串口就会打印断言freertos\portable\rvds\arm_cm3\port.c,244,在intrruptTask()里写一个while(1)即可解决。


问题解决了,可是为什么会这样?
先放出我的代码:

/*********************任务设置区*********************/
#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	120				//开始任务的堆栈大小,实际大小为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){
	//while(1);		//若此不加while(1),则会打印上述断言
}

运行结果
首先打印了一次的TIM3和TIM5,然后打印断言,然后打印TIM3。

我们再看port.c,244的源码,是一个函数:

static void prvTaskExitError( void )
{
	/* A function that implements a task must not exit or attempt to return to
	its caller as there is nothing to return to.  If a task wants to exit it
	should instead call vTaskDelete( NULL ).
	在执行任务时,不能退出或尝试返回到调用方,因为它没有需要返回的内容。
	如果此时需要退出任务,可以调用vTaskDelete( NULL )。
	Artificially force an assert() to be triggered if configASSERT() is
	defined, then stop here so application writers can catch the error. */
	configASSERT( uxCriticalNesting == ~0UL );
	portDISABLE_INTERRUPTS();
	for( ;; );
}

分析源码,可知
在出现问题的时候,该函数会先打印断言,然后调用portDISABLE_INTERRUPTS()关闭中断,由于TIM5可以被关闭,所以后面不会再打印TIM5,TIM3不会被关闭,则后面会继续打印TIM3。
根据注释,可分析得,在运行intrruptTask()的时候,由于没有死循环,运行一遍后需要返回,而正如注释所言:“在执行任务时,不能退出或尝试返回到调用方,因为它没有需要返回的内容。”所以会报错,解决方法就是加上死循环,这也就是为什么任务里都要有死循环。
当然你也可以不加死循环,直接调用vTaskDelete( NULL )把任务删了(NULL就是删除自己),也不会报错,比如这样:

void intrruptTask(void *pvParameters){
	/*你的任务代码*/
	vTaskDelete(NULL);
}

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值