FreeRTOS中任务挂起-恢复,与任务删除-创建的区别

背景

先说说背景:
1,我需要控制电机的运行,串口屏点击“运行”时,电机开始运行;串口屏点击“停止”时,电机停止运行。
因为这个电机是大功率的高速电机,需要通过与变频器进行通信来控制电机的转速,按照一定的加减速曲线来改变转速。
这个算法是我们单片机这边来实现的,我用了一个for循环,放在Run_Fun()和Stop_Fun()中。
2,为了实现电机停止的实时性,把Run_Fun()和Stop_Fun()放在了不同的线程中。

void Lcd_Display_Task_Func(void *argument)
{
	......
	
	while(1)
	{		
		......
		
		//执行停机逻辑
		Stop_Fun(countdown_timer);

		vTaskDelay(pdMS_TO_TICKS(50)); // 周期50ms
	}
	
}

void Ctrl_Task_Func(void *argument)
{
	......
	
    while(1)
    {
		......
		
		//控制函数:电机运行
        ctrl_driver.Ctrl(countdown_timer);
        vTaskDelay(pdMS_TO_TICKS(100)); // 周期100ms
    }
}

问题

好的,问题来了:

问题1

调试时发现,有时候点击“停止”时,电机的实时转速会出现一会增加、一会减小的现象。
分析了一下,应该是这样:
如果当前电机在加速过程中(即:在Run_Fun()里加速的for循环中),我们点击了“停止”,Stop_Fun()会开始减速。
此时就会出现:一会执行Stop_Fun()中减速的for循环,一会又会执行Run_Fun()中加速的for循环。
嗯,应该是这样。

解决1

怎么解决呢?
我们想要实现的目标是:一旦Stop_Fun()开始执行,Run_Fun()就停止执行,哪怕是正在for循环中。
这个简单呀,执行Stop_Fun()时,直接把Run_Fun()所在的任务挂起,到Stop_Fun()执行完之后,再恢复Run_Fun()所在的任务。
代码如下:

//执行停机逻辑
static void Stop_Fun(TimerHandle_t xTimer)
{
	/* 等待停止的信号量 */
	if (g_flag.stop)
	{
		g_flag.stop = 0;
		g_flag.run = 0;

        // 挂起 Ctrl_Task
        vTaskSuspend(Ctrl_TaskHandle);

		//停机操作
		......
		
        // 恢复 Ctrl_Task
        vTaskResume(Ctrl_TaskHandle);
	}	
}

问题2

按照上述方法,问题又来了:
每次电机完全停止之后,又会自动开始加速。
好奇怪,找了好久的原因,触发条件一个也没有满足啊

解决

终于,在多次调试之后,发现每次好像都是从上一次加速的速度又开始加速了。
每次都这样,应该是代码的问题吧,执行停机操作没啥问题,执行完之后,恢复了 Ctrl_Task。
哎? 不会是任务又从上一次挂起时的状态接着运行了吧。

果然,查了查资料:FreeRTOS中,vTaskSuspend 会挂起任务,但任务的状态和局部变量依然保留。这意味着,当你调用 vTaskResume 恢复任务时,任务会从上次停止的地方继续执行。

我们想要的是Ctrl_Task 从头开始运行,而不是恢复上次暂停的位置。那不如直接杀死并重新创建任务。

//执行停机逻辑
static void Stop_Fun(TimerHandle_t xTimer)
{
	/* 等待停止的信号量 */
	if (g_flag.stop)
	{
		g_flag.stop = 0;
		g_flag.run = 0;

        // 删除任务
        vTaskDelete(Ctrl_TaskHandle);

		//停机操作
		......
		
		// 重新创建任务
		osThreadAttr_t Ctrl_Task_attributes = {
			.name = "Ctrl_Task",
			.stack_size = 256 * 4,
			.priority = (osPriority_t) osPriorityNormal,
		};
		Ctrl_TaskHandle = osThreadNew(Ctrl_Task_Func, NULL, &Ctrl_Task_attributes);
	}	
}

果然,问题解决,其实只是对FreeRTOS中API的理解不够透彻。可能之前学习过,但没有实际踩坑就不算会了。
实践出真知啊。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值