主页

方案 #2
一个完整的占先式系统


<<< | >>>

简介

这是传统的占先式多任务方案。它完整的使用了 RTOS 服务而没有考虑内存和进程管理。包括一些部分功能简化的独立任务。


 

执行

系统的每个部分,或者有特别定时要求的部分,创建一个单独的任务。


解决方案 #2 任务函数和优先级

任务将被阻塞,直到有需要处理的事件发生。事件既可以外部事件(如有键按下),也可以是内部的(如定时器超时)。

优先级将按照任务的定时需求分配,高精度定时的要求分配高优先级。

 

操作的概念

最高优先级的任务在 RTOS 获得处理器权限时将被执行(不被阻塞)。当前任务将被内核立即悬挂使得高优先级可以执行。

这个调度将自动进行,无需在源代码中使用特别的知识、结构或命令。给任务分配合适的优先级是程序设计者的责任。

当没有任务执行时将执行空闲任务(idle task)。在空闲任务中可以使处理器休眠节约能源。

 

调度配置

调度管理配置为占先方式。内核节拍频率设置为需要时间间隔的最慢值。

 

评价

简单、分段、灵活、可维护的设计以及基本不相互关联。
处理器自动从一个任务切换到另一个,而不需要源代码中加入其他操作。

可以在空闲任务中加入节能指令(休眠)减少功率的消耗,但是系统节拍中断经常不必要的唤醒 CPU 会造成浪费。

核心功能使用了处理器资源,范围和内核节拍频率相关。
这个方案需要许多任务,每个任务有自己的堆栈,当发生事件时一些任务还需要队列。这个方案需要很多 RAM。
频繁的在相同优先级的任务间切换将浪费处理器时间。

 

结论

在 RAM 和 处理器性能足够时这是一个好的方案。系统划分为任务,并根据需要分配任务的优先级。


例子

这个例子是前面介绍的假想设备的一部分。使用了 FreeRTOS 的 API。

 

设备控制任务

这个任务完成所有控制功能。它有严格的定时要求,因此使用最高的优先级:
#define CYCLE_RATE_MS       10
#define MAX_COMMS_DELAY     2

void PlantControlTask( void *pvParameters )
{
portTickType xLastWakeTime;
DataType Data1, Data2;

    InitialiseTheQueue();

    // A
    xLastWakeTime = xTaskGetTickCount();

    // B
    for( ;; )
    {
        // C
        vTaskDelayUntil( &xLastWakeTime, CYCLE_RATE_MS );
        
        // Request data from the sensors.
        TransmitRequest();
        
        // D
        if( xQueueReceive( xFieldBusQueue, &Data1, MAX_COMMS_DELAY ) )
        {
            // E
            if( xQueueReceive( xFieldBusQueue, &Data2, MAX_COMMS_DELAY ) )
            {
                PerformControlAlgorithm();
                TransmitResults();                
            }
        } 
    }
    
    // Will never get here!   
}
上面代码中标签的说明:
  1. xLastWakeTime 初始化,这个变量用于 vTaskDelayUntil() API 函数,决定控制函数的调用频率。

  2. 这个函数作为独立的任务,因此从不退出。

  3. vTaskDelayUntil() 告诉内核这个任务将在保存在 xLastWakeTime 的时间后精确的 10ms 执行。到达这个时间后设备控制任务将进行任务阻塞。因为它是最高优先级任务,因此在时间到达后它将再次运行。它会抢占其他低优先级任务。

  4. 在数据请求和数据到达之间的时间间隔是有限的。从现场总线接收到的数据在中断服务程序中存放到 xFieldBusQueue,设备控制任务可以在队列中进行阻塞调用,等待数据到达。和以前一样,因为它是系统中最高优先级任务,所以数据到达后它将立即执行。

  5. 类似 'D', 等待第二个传感器的数据。

从 xQueueReceive() 返回 0 代表在指定的阻塞时间里没有接收到数据,这是任务必须处理的错误。为了进行简化,没有写出错误处理部分。

 

嵌入式 WEB 服务器任务

嵌入式 WEB 服务器任务可以用下面的伪代码表示。这是唯一可能占用较长处理器时间的任务,当接收到数据时它需要相对较长的时间完成处理。它使用了低优先级,防止影响到设备控制、RS232 或键盘扫描任务。
void WebServerTask( void *pvParameters )
{
DataTypeA Data;

    for( ;; )
    {
        // Block until data arrives.  xEthernetQueue is filled by the
        // Ethernet interrupt service routine.
        if( xQueueReceive( xEthernetQueue, &Data, MAX_DELAY ) )
        {
            ProcessHTTPData( Data );
        }        
    }
}

 

RS232 接口

在结构上它非常类似于嵌入式 WEB 服务器任务,使用中等优先级以保证不会影响到设备控制任务。
void RS232Task( void *pvParameters )
{
DataTypeB Data;

    for( ;; )
    {
        // Block until data arrives.  xRS232Queue is filled by the
        // RS232 interrupt service routine.
        if( xQueueReceive( xRS232Queue, &Data, MAX_DELAY ) )
        {
            ProcessSerialCharacters( Data );
        }        
    }
}

 

键盘扫描任务

这是一个简单的周期性任务。 它给定中等优先级,因为它的定时要求和 RS232 任务类似。

设置的定时周期比指定的门限高很多。这是因为发出请求后可能不能马上进行处理 - 可能被设备控制任务抢占。

#define DELAY_PERIOD 4

void KeyScanTask( void *pvParmeters )
{
char Key;
portTickType xLastWakeTime;

    xLastWakeTime = xTaskGetTickCount();

    for( ;; )
    {
        // Wait for the next cycle.
        vTaskDelayUntil( &xLastWakeTime, DELAY_PERIOD );
        
        // Scan the keyboard.
        if( KeyPressed( &Key ) )
        {
            UpdateDisplay( Key );
        }
    }
}

如果把所有空闲的系统时间都用于这个任务,那么可以设置它为优先级最低的任务,这样完全可以删除 vTaskDelayUntil() 函数。键盘扫描函数将连续执行直到被其他高优先级任务阻塞 - 相当于空闲任务(idle task)。

 

LED 任务

这是所有任务中最简单的一个。
#define DELAY_PERIOD 1000

void LEDTask( void *pvParmeters )
{
portTickType xLastWakeTime;

    xLastWakeTime = xTaskGetTickCount();

    for( ;; )
    {
        // Wait for the next cycle.
        vTaskDelayUntil( &xLastWakeTime, DELAY_PERIOD );

        // Flash the appropriate LED.
        if( SystemIsHealthy() )
        {
            FlashLED( GREEN );
        }
        else
        {
            FlashLED( RED );
        }        
    }
}

下一节 >>> 方案 #3: 减少 RAM 使用率

 


翻译:   邵子扬
EMail:   shaoziyang@126.com
Blog:    http://blog.ednchina.com/shaoziyang
2008年10月

 

Site Meter