FreeRTOS中的状态机程序设计——switch语句中的vTaskStartScheduler
State machine program design in FreeRTOS - vTaskStartScheduler in a switch statement
我在 FreeRTOS 中有一个程序设计问题:
我有一个有 4 个状态和 6 个任务的状态机。在每个状态下,必须执行不同的任务,但 Task1 除外,它始终处于活动状态:
状态 1:任务 1、任务 2、任务 3
状态 2:任务 1、任务 2、任务 3、任务 4
状态 3:任务 1、任务 5
状态 4:任务 1、任务 6
Task1、Task3、Task4、Task5 和 Task6 是周期性的,每个读取不同的传感器。
Task2 是非周期性的,它仅在达到阈值时才发送 GPRS 警报。
状态之间的切换由来自每个任务的传感器输入的事件决定。
main()的最初设计思路是有一个开关来控制状态,并根据状态暂停和激活相应的任务:
void main ()
{
/* initialisation of hw and variables*/
system_init();
/* creates FreeRTOS tasks and suspends all tasks except Task1*/
task_create();
/* Start the scheduler so FreeRTOS runs the tasks */
vTaskStartScheduler();
while(true)
{
switch STATE:
case 1:
suspend(Task4, Task5, Task6);
activate(Task2, Task3);
break;
case 2:
suspend(Task5, Task6);
activate(Task2, Task3, Task4);
break;
case 3:
suspend(Task2, Task3, Task4, Task6);
activate(Task5);
break;
case 4:
suspend(Task2, Task3, Task4, Task5);
activate(Task6);
break;
}
}
我的问题是:我应该在哪里调用与开关相关的 vTaskStartScheduler()?在我看来,在这段代码中,一旦调用了vTaskStartScheduler,程序就永远不会进入switch语句。
我是否应该创建另一个始终处于活动状态的任务来控制状态机,其中包含前面的 while 和 switch 语句,例如以下伪代码?
task_control()
{
while(true)
{
switch STATE:
case 1:
suspend(Task4, Task5, Task6);
execute(Task2, Task3);
and so on...
}
}
任何建议将不胜感激...
为了回答您的问题,vTaskStartScheduler()
顾名思义,将启动调度程序。它之后的任何代码只会在调度程序停止时执行,这在大多数情况下是程序结束时,所以永远不会。这就是为什么您的 switch
不会 运行.
正如您已经避开的那样,对于您的设计,您可以使用 'main' 任务来控制其他任务。在调用 vTaskStartScheduler()
.
之前,您需要创建它并向调度程序注册它
附带说明一下,如果您确实采用这种方法,您只想 suspend/resume 您的任务在第一次进入某个状态时执行,而不是在 'main' 任务的每次迭代时执行。
例如:
static bool s_first_state_entry = true;
task_control()
{
while (true)
{
switch (STATE)
{
case 1:
if (s_first_state_entry)
{
// Only do this stuff once
s_first_state_entry = false;
suspend(Task4, Task5, Task6);
execute(Task2, Task3);
}
// Do this stuff on every iteration
// ...
break;
default:
break;
}
}
}
void set_state(int state)
{
STATE = state;
s_first_state_entry = true;
}
正如 Ed King 所提到的,您的解决方案包含一个主要的设计缺陷。也就是说 - 在启动调度程序之后,在调度程序停止之前,在主函数中指定的任何代码都不会执行。
我建议在 Idle 任务中实现你的状态逻辑(记住在你的任务中包含延迟,不要让 Idle 挂钩因处理时间而饿死)。空闲任务可以根据信号量的当前状态阻塞和解除阻塞任务。不过请记住,Idle 挂钩是一项优先级最低的任务,因此在设计系统时要小心。当任务消耗大部分处理时间不允许空闲任务切换状态时,我建议的解决方案可能是完全错误的。
或者,您可以创建 Ed King 提到的具有最高优先级的高级任务。
老实说,一切都取决于任务真正在做什么。
我在 FreeRTOS 中有一个程序设计问题:
我有一个有 4 个状态和 6 个任务的状态机。在每个状态下,必须执行不同的任务,但 Task1 除外,它始终处于活动状态:
状态 1:任务 1、任务 2、任务 3
状态 2:任务 1、任务 2、任务 3、任务 4
状态 3:任务 1、任务 5
状态 4:任务 1、任务 6
Task1、Task3、Task4、Task5 和 Task6 是周期性的,每个读取不同的传感器。
Task2 是非周期性的,它仅在达到阈值时才发送 GPRS 警报。
状态之间的切换由来自每个任务的传感器输入的事件决定。
main()的最初设计思路是有一个开关来控制状态,并根据状态暂停和激活相应的任务:
void main ()
{
/* initialisation of hw and variables*/
system_init();
/* creates FreeRTOS tasks and suspends all tasks except Task1*/
task_create();
/* Start the scheduler so FreeRTOS runs the tasks */
vTaskStartScheduler();
while(true)
{
switch STATE:
case 1:
suspend(Task4, Task5, Task6);
activate(Task2, Task3);
break;
case 2:
suspend(Task5, Task6);
activate(Task2, Task3, Task4);
break;
case 3:
suspend(Task2, Task3, Task4, Task6);
activate(Task5);
break;
case 4:
suspend(Task2, Task3, Task4, Task5);
activate(Task6);
break;
}
}
我的问题是:我应该在哪里调用与开关相关的 vTaskStartScheduler()?在我看来,在这段代码中,一旦调用了vTaskStartScheduler,程序就永远不会进入switch语句。
我是否应该创建另一个始终处于活动状态的任务来控制状态机,其中包含前面的 while 和 switch 语句,例如以下伪代码?
task_control()
{
while(true)
{
switch STATE:
case 1:
suspend(Task4, Task5, Task6);
execute(Task2, Task3);
and so on...
}
}
任何建议将不胜感激...
为了回答您的问题,vTaskStartScheduler()
顾名思义,将启动调度程序。它之后的任何代码只会在调度程序停止时执行,这在大多数情况下是程序结束时,所以永远不会。这就是为什么您的 switch
不会 运行.
正如您已经避开的那样,对于您的设计,您可以使用 'main' 任务来控制其他任务。在调用 vTaskStartScheduler()
.
附带说明一下,如果您确实采用这种方法,您只想 suspend/resume 您的任务在第一次进入某个状态时执行,而不是在 'main' 任务的每次迭代时执行。
例如:
static bool s_first_state_entry = true;
task_control()
{
while (true)
{
switch (STATE)
{
case 1:
if (s_first_state_entry)
{
// Only do this stuff once
s_first_state_entry = false;
suspend(Task4, Task5, Task6);
execute(Task2, Task3);
}
// Do this stuff on every iteration
// ...
break;
default:
break;
}
}
}
void set_state(int state)
{
STATE = state;
s_first_state_entry = true;
}
正如 Ed King 所提到的,您的解决方案包含一个主要的设计缺陷。也就是说 - 在启动调度程序之后,在调度程序停止之前,在主函数中指定的任何代码都不会执行。
我建议在 Idle 任务中实现你的状态逻辑(记住在你的任务中包含延迟,不要让 Idle 挂钩因处理时间而饿死)。空闲任务可以根据信号量的当前状态阻塞和解除阻塞任务。不过请记住,Idle 挂钩是一项优先级最低的任务,因此在设计系统时要小心。当任务消耗大部分处理时间不允许空闲任务切换状态时,我建议的解决方案可能是完全错误的。
或者,您可以创建 Ed King 提到的具有最高优先级的高级任务。
老实说,一切都取决于任务真正在做什么。