FreeRTOS内有croutine这个驱动,但是,这个怎么翻译,我也不太明白,暂且脑补成协程,就是co-routine,这个用起来跟任务比较类似,只不过他调用每个东西,都像一个函数一样,不像一个任务,就是说,任务是Cortex-A的话,这协程能做的就是Cortex-M的,他们并不能吃多少内存,也不能干太多什么事.但是协程一样要调度的,受任务控制,一般在IDLE任务里面搞.通常的表达是这样的.
void vApplicationIdleHook( void ) { for( ;; ) { vCoRoutineSchedule(); } }
当然,如果Idle里面还有别的任务,可就不能死循环了.当然,其他任务也把时间片全用了,那我自然也没机会执行.当然,要做这个,需要打开configUSE_CO_ROUTINES开关.协程时间准确性也比较差.比如我闪烁一个LED灯.
void vFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ) { crSTART( xHandle ); for( ;; ) { if(uxIndex == 0) { GPIO_ToggleBits(GPIOG, GPIO_Pin_13); crDELAY( xHandle, 500 ); } else if(uxIndex == 1) { GPIO_ToggleBits(GPIOG, GPIO_Pin_14); crDELAY( xHandle, 1000 ); } } crEND(); }
发现,这个程序必须有两个参数,一个是xHandle,自己的句柄,另一个是uxIndex,传入的参数.是Index,所以,只能按数字传.协程必须以crSTART开始,以crEND结束,协程内的延迟,使用crDELAY.实验效果就是,主任务Task并不受干扰,LED还能正常闪烁.完整程序如下,忽略IO初始化.
#include "FreeRTOS.h" #include "task.h" #include "croutine.h" void vApplicationIdleHook( void ) { vCoRoutineSchedule(); } static void vTask1( void *pvParameters ) { portTickType xLastWakeTime; xLastWakeTime = xTaskGetTickCount(); for( ;; ) { printf("Hello 3000!"); vTaskDelayUntil( &xLastWakeTime, ( 3000 / portTICK_RATE_MS ) ); } } static void vTask2( void *pvParameters ) { portTickType xLastWakeTime; xLastWakeTime = xTaskGetTickCount(); for( ;; ) { printf("Hello 2000!"); vTaskDelayUntil( &xLastWakeTime, ( 1000 / portTICK_RATE_MS ) ); } } void vFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ) { crSTART( xHandle ); for( ;; ) { if(uxIndex == 0) { GPIO_ToggleBits(GPIOG, GPIO_Pin_13); crDELAY( xHandle, 500 ); } else if(uxIndex == 1) { GPIO_ToggleBits(GPIOG, GPIO_Pin_14); crDELAY( xHandle, 1000 ); } } crEND(); } int main(void) { xTaskCreate( vTask1, ( const char * ) "vTask1", 1000, NULL, 1, NULL ); xTaskCreate( vTask2, ( const char * ) "vTask2", 1000, NULL, 1, NULL ); xCoRoutineCreate( vFlashCoRoutine, 0, 0 ); xCoRoutineCreate( vFlashCoRoutine, 0, 1 ); vTaskStartScheduler(); for(;;); }
协程非常简单,而且优先级很低,适合做后台应用.