FreeRTOS中的状态机程序设计 - 在switch语句中的vTaskStartScheduler

时间:2017-10-11 10:01:13

标签: operating-system embedded state-machine atmel freertos

我在FreeRTOS中有一个程序设计问题:

我有一个状态机,有4个状态和6个任务。在每个状态中,必须执行不同的任务,但Task1除外,它始终处于活动状态:

状态1:任务1,任务2,任务3
状态2:Task1,Task2,Task3,Task4
状态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...
    }
}  

任何建议都将不胜感激......

2 个答案:

答案 0 :(得分:1)

要回答您的问题,vTaskStartScheduler()将顾名思义启动调度程序。之后的任何代码只会在调度程序停止时执行,这在大多数情况下是程序结束时,所以永远不会。这就是您switch赢了的原因。

正如您已经想到的那样,对于您的设计,您可以使用' main'控制其他人的任务。您需要创建此项并在调用vTaskStartScheduler()之前将其注册到调度程序。

另一方面,如果你采用这种方法,你只想在第一次进入状态时暂停/恢复你的任务,而不是在主要'的每次迭代中暂停/恢复你的任务。任务。

例如:

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;
}

答案 1 :(得分:0)

正如Ed King所说,你的解决方案包含一个主要的设计缺陷。也就是说 - 在启动调度程序之后,在调度程序停止之前,在main函数中指定的代码之后都不会执行。

我建议在空闲任务中实现您的状态逻辑(记住在您的任务中包含延迟,以免使Idle挂钩处于处理时间之外)。空闲任务可以根据信号量的menas当前状态阻止和解除阻塞任务。但请记住,Idle挂钩是具有最低优先级的任务,因此在设计系统时要小心。当任务占用大部分处理时间而不允许空闲任务切换状态时,我建议的解决方案可能完全错误。

或者,您可以创建Ed King所提及的优先任务,具有最高优先级。

说实话,一切都取决于任务的实际作用。