<<< | >>>
注意:这些网页自从 FreeRTOS V4.0.0 后就没有更新了。V4.0.0 介绍联合程序的概念,提供了和这里不同的方法。在 任务和联合程序 文档中进一步说明了这些内容。
混合调度算法(不是完全的占先或协作)是先将内核配置为协作调度,然后在事件中断服务程序中进行任务切换。
设备控制函数以高优先级任务运行,但是使用协作调度需要使它做出一些修改。使用 vTaskDelayUntil() API 函数保存上一次的时间。当使用占先调度时,分配控制任务成为最高优先级任务,保证它精确的在指定时间运行。现在使用协作调度后 - 因此任务切换将只在程序代码中明确请求后才会进行,必然会损失时间。
方案 #4 使用定时器外设中断保证请求的任务切换准确按照控制任务的频率。调度保证每次请求的任务将切换到需要运行的最高优先级任务。
键盘扫描函数也需要固定的处理时间,这样它可以由定时器中断触发。这个任务的时间可以很容易计算出来,最坏的情况下控制函数的处理时间由错误情况给定 - 当没有收到网络传感器的数据引起控制函数超时。键盘扫描函数执行时间是基本固定的,因此我们可以确定这种机制不会影响控制周期的变化 - 或者丢失控制周期。
RS232 任务将由 RS232 中断服务程序调度。
LED 函数的可变定时要求意味着它可以和嵌入式 WEB 服务器任务一样加入到空闲任务的钩子中。如果这不能满足要求那么也可以移到高优先级任务中。
RS232 或定时器外设引起的中断只有在确实需要时才进行任务切换。这种方式 RS232 任务将继续占先空闲任务,并且它也可以被设备控制任务占先 - 保持系统的优先级机制。
![]() |
只创建两个系统任务,所以使用的内存比方案 #2 少很多。 |
![]() |
RTOS 进程开销减少到最小。 |
![]() |
只使用了 RTOS 的部分功能,这需要在源代码级仔细考虑定时和运行环境,但是仍然极大的简化了设计(比较方案 #1)。 |
![]() |
依赖处理器的外设,不可移植。 |
![]() |
模块之间的问题分析和相互依赖和方案 #1 一样变得需要再次考虑 - 尽管范围小多了。 |
![]() |
当系统变得很大时设计可能不足。 |
这个例子是假想系统的一部分。使用了 FreeRTOS.org API。
void vTimerInterrupt( void ) { // 'Give' the semaphore. This will wake the high priority task. xSemaphoreGiveFromISR( xTimingSemaphore ); // The high priority task will now be able to execute but as // the cooperative scheduler is being used it will not start // to execute until we explicitly cause a context switch. taskYIELD(); }注意这里用于从 ISR 中切换任务的语法可能与你使用的处理器不同,不要直接复制这个例子的用法,而是先查看你正在移植的处理器的文档。
高优先级任务包括了设备控制任务和键盘函数。先调用 PlantControlCycle() 保证定时的一致性 。
void HighPriorityTaskTask( void *pvParameters ) { // Start by obtaining the semaphore. xSemaphoreTake( xSemaphore, DONT_BLOCK ); for( ;; ) { // Another call to take the semaphore will now fail until // the timer interrupt has called xSemaphoreGiveFromISR(). // We use a very long block time as the timing is controlled // by the frequency of the timer. if( xSemaphoreTake( xSemaphore, VERY_LONG_TIME ) == pdTRUE ) { // We unblocked because the semaphore became available. // It must be time to execute the control algorithm. PlantControlCycle(); // Followed by the keyscan. if( KeyPressed( &Key ) ) { UpdateDisplay( Key ); } } // Now we go back and block again until the next timer interrupt. } }
RS232 任务的伪代码如下:
void vRS232Task( void *pvParameters ) { DataType Data; for( ;; ) { if( cQueueReceive( xRS232Queue, &Data, MAX_DELAY ) ) { ProcessRS232Data( Data ); } } }
void IdleTaskHook( void ) { static portTickType LastFlashTime = 0; ProcessHTTPRequests(); // Check the tick count value to see if it is time to flash the LED // again. if( ( xTaskGetTickCount() - LastFlashTime ) > FLASH_RATE ) { UpdateLED(); // Remember the time now so we know when the next flash is due. LastFlashTime = xTaskGetTickCount(); } }
翻译: 邵子扬
EMail: shaoziyang@126.com
Blog: http://blog.ednchina.com/shaoziyang
2008年10月