2-协程
2.1-协同状态
协程仅适用于对RAM有限制的处理器,一般情况下32位MCU是不会使用的(在这里还是给大家说一下,基础理论知识就全点)。
2.1.1 运行当协程实际执行时,我们称其处于运行状态。当前处理器正在工作。2.1.2 就绪就绪的协程是那些能够执行(它们没有被阻塞)但目前没有执行的。协程可能处于Ready状态,一是 另一个具有同等或更高优先级的协程已经处于Running状态;二是任务处于Running状态(只有当应用程序同时使用任务和协程时,才会出现这种情况)。2.1.3 阻塞
如果一个协程当前正在等待一个临时或外部事件,那么它就被称为处于Blocked状态。例如,如果一个协程调用crDELAY(),它将阻塞(被置于阻塞状态),直到延迟周期超时,一个临时事件。阻塞的协程无法用于调度。
下面是协程的通信图:
2.2 协程的实现
协程的结构如下:
1void vACoRoutineFunction( CoRoutineHandle_t xHandle, 2UBaseType_t uxIndex ) 3{ 4crSTART( xHandle ); 5 6for( ;; ) 7{ 8-- Co-routine application code here. -- 9} 10 11crEND(); 12}
类型crCOROUTINE_CODE被定义为一个返回void并将CoRoutineHandle_t和索引作为参数的函数。实现协程的所有函数都应该是这种类型的(上面的这段代码)。
协程的创建是通过xCoRoutineCreate()来进行的。
注意:
所有协程函数都必须以调用crSTART()开始。
所有协程函数都必须以对crEND()的调用结束。
协程函数不应该返回,因此通常作为连续循环实现。
可以从单个协程函数创建许多协程。
提供 uxIndex 参数是为了区分此类 协程。
2.3-协程优先级
协程的优先级从0到(configMAX_CO_ROUTINE_PRIORITIES - 1)。configMAX_CO_ROUTINE_PRIORITIES在FreeRTOSConfig.h中定义,可以在应用程序的基础上设置。优先级和任务一样数字越大优先级越高。
协程优先级只与其他协程相关。如果在同一个应用程序中混合了任务和协程,那么任务的优先级始终比协程的优先级高。
2.4- 协程调度
协程是通过重复调用vCoRoutineSchedule() 来调度的。调用 vCoRoutineSchedule() 的最佳位置是从空闲任务钩子。即使您的应用程序只使用协程,也会出现这种现象,因为空闲任务仍将在调度程序启动时自动创建。
2.5- 协程和任务的混合
在空间任务中调度协程是允许任务和协程的混合的。这种方式只有当协程优先级低于空闲任务的优先级时,这种方式下才能执行。
2.5.1-局限性和复杂性和任务相比来说,协程的好处是降低了RAM的使用空间,但是这些也会带来一定的限制。比如局限性以及复杂性。2.5.2堆栈共享当协程阻塞时,携程的堆栈时不会被保存的,这样即使在堆栈上有再多的变量,也会丢失。因此为了能够解决这个问题,需要声明一个在阻塞时保持调用的变量,作为静态。例如:
1void vACoRoutineFunction( CoRoutineHandle_t xHandle, 2UBaseType_t uxIndex ) 3{ 4static char c = 'a'; 5 6// Co-routines must start with a call to crSTART(). 7crSTART( xHandle ); 8 9for( ;; ) 10{ 11// If we set c to equal 'b' here ... 12c = 'b'; 13 14// ... then make a blocking call ... 15crDELAY( xHandle, 10 ); 16 17// ... c will only be guaranteed to still 18// equal 'b' here if it is declared static 19// (as it is here). 20} 21 22// Co-routines must end with a call to crEND(). 23crEND(); 24}
堆栈共用的另一种结果是,可能导致协程阻塞API函数的调用只能来自于协程函数本身,而不是协程函数调用的函数。
1例如: 2void vACoRoutineFunction( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ) 3{ 4// Co-routines must start with a call to crSTART(). 5crSTART( xHandle ); 6 7for( ;; ) 8{ 9// It is fine to make a blocking call here, 10crDELAY( xHandle, 10 ); 11 12// but a blocking call cannot be made from within 13// vACalledFunction(). 14vACalledFunction(); 15} 16 17// Co-routines must end with a call to crEND(). 18crEND(); 19} 20 21void vACalledFunction( void ) 22{ 23// Cannot make a blocking call here! 24}
2.5.3 switch语句的应用FreeRTOS文件中包含的默认协程实现不允许从switch语句中进行阻塞调用。
1void vACoRoutineFunction( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ) 2{ 3// Co-routines must start with a call to crSTART(). 4crSTART( xHandle ); 5 6for( ;; ) 7{ 8// It is fine to make a blocking call here, 9crDELAY( xHandle, 10 ); 10 11switch( aVariable ) 12{ 13case 1 : // Cannot make a blocking call here! 14break; 15default: // Or here! 16} 17} 18 19// Co-routines must end with a call to crEND(). 20crEND(); 21}
2.6协程例子2.6.1 创建LED协程
1void vFlashCoRoutine( CoRoutineHandle_t xHandle, 2UBaseType_t uxIndex ) 3{ 4// Co-routines must start with a call to crSTART(). 5crSTART( xHandle ); 6 7for( ;; ) 8{ 9// Delay for a fixed period. 10crDELAY( xHandle, 10 ); 11 12// Flash an LED. 13vParTestToggleLED( 0 ); 14} 15 16// Co-routines must end with a call to crEND(). 17crEND(); 18}
2.6.2 协程调度
协同例程是通过重复调用 vCoRoutineSchedule()来调度的。执行此操作的最佳位置是从空闲任务中编写空闲任务挂钩。首先确保在FreeRTOSConfig.h 中将configUSE_IDLE_HOOK设置为 1。然后将空闲任务钩子编写为:
1void vApplicationIdleHook( void ) 2{ 3vCoRoutineSchedule( void ); 4} 5或者,如果空闲任务不执行任何其他函数,从循环中调用vCoRoutineSchedule()会更有效: 6void vApplicationIdleHook( void ) 7{ 8for( ;; ) 9{ 10vCoRoutineSchedule( void ); 11} 12}
2.6.3 创建协程并启动RTOS调度
1#include "task.h" 2#include "croutine.h" 3 4#define PRIORITY_0 0 5 6void main( void ) 7{ 8// In this case the index is not used and is passed 9// in as 0. 10xCoRoutineCreate( vFlashCoRoutine, PRIORITY_0, 0 ); 11 12// NOTE: Tasks can also be created here! 13 14// Start the RTOS scheduler. 15vTaskStartScheduler(); 16}
2.6.4 扩展现在假设我们要从同一个函数创建 8 个这样的协程。每个协程将闪烁不同的 LED 以不同的速率显示。index 参数可用于区分协程函数本身。
1#include "task.h" 2#include "croutine.h" 3 4#define PRIORITY_0 0 5#define NUM_COROUTINES 8 6 7void main( void ) 8{ 9int i; 10 11for( i = 0; i < NUM_COROUTINES; i++ ) 12{ 13// This time i is passed in as the index. 14xCoRoutineCreate( vFlashCoRoutine, PRIORITY_0, i ); 15} 16 17// NOTE: Tasks can also be created here! 18 19// Start the RTOS scheduler. 20vTaskStartScheduler(); 21} 22还扩展了协程功能,因此每个程序都使用不同的LED和闪光率。 23const int iFlashRates[ NUM_COROUTINES ] = { 10, 20, 30, 40, 50, 60, 70, 80 }; 24const int iLEDToFlash[ NUM_COROUTINES ] = { 0, 1, 2, 3, 4, 5, 6, 7 } 25 26void vFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ) 27{ 28// Co-routines must start with a call to crSTART(). 29crSTART( xHandle ); 30 31for( ;; ) 32{ 33// Delay for a fixed period. uxIndex is used to index into 34// the iFlashRates. As each co-routine was created with 35// a different index value each will delay for a different 36// period. 37crDELAY( xHandle, iFlashRate[ uxIndex ] ); 38 39// Flash an LED. Again uxIndex is used as an array index, 40// this time to locate the LED that should be toggled. 41vParTestToggleLED( iLEDToFlash[ uxIndex ] ); 42} 43 44// Co-routines must end with a call to crEND(). 45crEND(); 46}
****因个人创作与翻译,难免有错误地方,希望各位道友指正。我会在后面CSDN进行修改(公众号当前只支持修改20个字)。*****