主页

方案 #3
减少 RAM 使用率

<<< | >>>

注意:这些网页自从 FreeRTOS V4.0.0 后就没有更新了。V4.0.0 介绍联合程序的概念,提供了和这里不同的方法。在 任务和联合程序 文档中进一步说明了这些内容。

 

摘要

方案 #2 完整的使用了 RTOS。这是个不错的设计,但是它只能用在 RAM 和处理器资源丰富的微处理器上。方案 #3 试图修改函数和任务的划分来减少 RAM 的使用率。


 

执行


方案 #3 函数任务和优先级

我们再查看前面,假想的系统的定时可以分为3类:

  1. 严格定时 - 设备控制 和前面一样,创建高优先级任务严格管理控制函数。

  2. 时限定时 - 人机接口 方案 #3 中包括了 RS232、键盘和 LED 函数,归类到单一的中等优先级任务。

    因为前面说明过的原因,嵌入式 WEB 服务器任务是低优先级任务。单独创建 WEB 服务任务不如在空闲任务的钩子中添加 WEB 服务器函数,不过 WEB 服务器必须保证它从不被阻塞!

  3. 可变定时 - LED

    LED 函数非常简单,以致无需担心任务的 RAM 问题。在这个例子中 LED 函数是单一的中优先级任务,它可以用多种方式执行(例子中是从定时器中)。

除了空闲任务以外的任务将被阻塞直到发生一个事件表明需要任务进行处理。事件既可以是外部事件(如按键),或者是内部事件(如定时器超时)。

 

操作的概念

将函数变为中等优先级任务,相比方案 #1 的无限循环方式有3个主要的优点:
  1. 队列的使用允许中等优先级任务被阻塞直到有数据可以使用时发生事件 - 然后立即跳转到相关的函数处理事件。这样就不会浪费处理器时间 - 作为对比无限循环方式下事件只有在循环到对应的处理标志才能处理。

  2. 使用实时内核可以不用在用户程序源代码中考虑怎样调度保证严格定时要求的任务。

  3. 将嵌入式 WEB 服务器函数从循环中删除后,程序的运行时间变得容易预测了。

此外,变成一个任务或多个任务的函数,使用同样的优先级(LED 函数)。这个优先级代码的执行频率不会因为是一个或者多个任务而改变。

设备控制任务作为最高优先级任务,保证了在任何需要的时候就可以分配到处理器时间,在需要时它将占先低优先级和中优先级任务。空闲任务在所有任务阻塞时执行,可以设置选项在空闲任务中使处理器进入节能模式。

 

调度配置

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

 

评价

只创建了两个任务,比方案 #2 占用的 RAM 少很多。
处理器自动切换到最紧急的任务。
利用空闲任务有效的将3个优先级的任务变成2个。
设计虽然简单,但是中等优先级任务函数执行时间可能会引起问题 。分开的嵌入式 WEB 服务器任务减少了这个风险,将不会影响设备控制任务。
如果在空闲任务中加入休眠指令可以节约能源,但是系统节拍中断经常不必要的唤醒 CPU 会造成浪费。

RTOS 函数使用了处理器资源,范围和内核节拍频率相关。

当系统变得很大时设计可能不足。

 

结论

这对于 RAM 有限的系统是个好的方案,但是仍然对处理器要求较高。系统剩余的能力可以允许用于进一步扩充。


例子

这个例子是假想系统的一部分。使用了 FreeRTOS.org API。

 

设备控制任务

设备控制任务和 方案 #2 中完全一样。

 

嵌入式 WEB 服务器

这是一个简单的函数,从空闲任务中调用,运行直到完成。

 

中等优先级任务

中等优先级任务可以用下面伪代码表示。
#define DELAY_PERIOD 4
#define FLASH_RATE 1000

void MediumPriorityTask( void *pvParameters )
{
xQueueItem Data;
portTickType FlashTime;

    InitialiseQueue();
    FlashTime = xTaskGetTickCount();
    
    for( ;; )
    {
        do
        {
            // A
            if( xQueueReceive( xCommsQueue, &Data, DELAY_PERIOD ) )
            {
                ProcessRS232Characters( Data.Value );
            }
            
          // B
        } while ( uxQueueMessagesWaiting( xCommsQueue ) );
        
        // C
        if( ScanKeypad() )
        {
            UpdateLCD();
        }
        
        // D
        if( ( xTaskGetTickCount() - FlashTime ) >= FLASH_RATE )
        {
            FlashTime = xTaskGetTickCount();
            UpdateLED();
        }
    }

    // Should never get here.
    return 0;
}
上面代码段中的标签说明如下:
  1. 任务首先阻塞等待通信时间。阻塞时间相对很短。

  2. 执行 do-while 循环直到队列中没有数据。这个方法在数据到达太快以致队列还没有处理完时需要进行修改。

  3. 队列中数据为空或在指定的阻塞时间里没有数据到达。最大的阻塞时间必须足够短,保证键盘扫描频率足够快,满足指定的时间限制。

  4. 检查是否达到闪烁 LED 的时间。执行这一行的频率可能会有些小变化,但是 LED 需要的定时足够灵活,可以满足这里的要求。


下一节 >>> 方案 #4: 减少处理器开销


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

 

Site Meter