FreeRTOS——协同程序(Co-routine)( 二 )


低优先级数字表示低优先级协程 。
协同例程的优先级仅与其他协同例程有关 。如果您在同一应用程序中混合使用任务和协同例程 , 则任务将始终优先于协同例程 。
调度协同例程通过重复调用vCoRoutineSchedule()来调度协同例程 。调用vCoRoutineSchedule()的最佳位置是从空闲任务挂钩中进行 。即使您的应用程序仅使用协同例程 , 也是如此 , 因为在启动调度程序时仍将自动创建空闲任务 。请参阅后面的示例 。
混合使用任务和常规程序从空闲任务中调度协同例程可以使任务和协同例程轻松混合在同一应用程序中 。完成此操作后 , 协同例程将仅在没有比执行的空闲任务高的优先级的任务时执行 。请参阅后面的示例 。
局限性与同等任务相比 , 协同例程的RAM使用量较低的好处是 , 对协同例程的使用方式存在一些限制 。协同例程比任务更具限制性和复杂性 。

  • 共享堆栈
当协同例程阻塞时 , 不维护该协同例程的堆栈 。这意味着在堆栈上分配的变量很可能会丢失其值 。为了克服这个问题 , 必须将必须在阻塞调用中保持其值的变量声明为静态变量 。例如:
void vACoRoutineFunction( CoRoutineHandle_t xHandle,UBaseType_t uxIndex ){static char c = 'a';// Co-routines must start with a call to crSTART().crSTART( xHandle );for( ;; ){// If we set c to equal 'b' here ...c = 'b';// ... then make a blocking call ...crDELAY( xHandle, 10 );// ... c will only be guaranteed to still// equal 'b' here if it is declared static// (as it is here).}// Co-routines must end with a call to crEND().crEND();}共享堆栈的另一个结果是 , 可能导致协同例程阻塞的对API函数的调用只能从协同例程函数本身进行 , 而不能从协同例程调用的函数内部进行 。例如:
void vACoRoutineFunction( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ){// Co-routines must start with a call to crSTART().crSTART( xHandle );for( ;; ){// It is fine to make a blocking call here,crDELAY( xHandle, 10 );// but a blocking call cannot be made from within// vACalledFunction().vACalledFunction();}// Co-routines must end with a call to crEND().crEND();}void vACalledFunction( void ){// Cannot make a blocking call here!}
  • 使用switch语句
FreeRTOS下载中包含的默认协同例程实现不允许在switch语句中进行阻塞调用 。例如:
void vACoRoutineFunction( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ){// Co-routines must start with a call to crSTART().crSTART( xHandle );for( ;; ){// It is fine to make a blocking call here,crDELAY( xHandle, 10 );switch( aVariable ){case 1 : // Cannot make a blocking call here!break;default: // Or here!}}// Co-routines must end with a call to crEND().crEND();}快速例程示例这个简单的示例演示了协同例程的用法 。
  • 创建一个简单的例程以使LED闪烁以下代码定义了一个非常简单的协同例程 , 该例程不执行任何操作 , 但会定期使LED闪烁 。
void vFlashCoRoutine( CoRoutineHandle_t xHandle,UBaseType_t uxIndex ){// Co-routines must start with a call to crSTART().crSTART( xHandle );for( ;; ){// Delay for a fixed period.crDELAY( xHandle, 10 );// Flash an LED.vParTestToggleLED( 0 );}// Co-routines must end with a call to crEND().crEND();}
  • 调度协同例程
通过重复调用vCoRoutineSchedule()来调度协同例程 。最好的方法是从空闲任务中编写一个空闲任务挂钩 。首先确保在FreeRTOSConfig.h中将configUSE_IDLE_HOOK设置为1 。然后将空闲任务挂钩写为: