FreeRTOS 协同程序

FreeRTOS 协同程序

协同程序是一种特殊的多任务编程方式,多个协同程序之间共用调用栈,且正在运行的协同程序不会被其他协程抢占(可以被任务和中断抢占),正在运行的协同程序只能自己主动让出CPU的使用权。要使用协同程序,需要将FreeRTOSConfig.h中的configUSE_CO_ROUTINES设为1

FreeRTOS的协同程序采用switch-case实现,函数定义方式如下:

void CoRoutineTask(CoRoutineHandle_t handle,UBaseType_t uxIndex)
{
    //协同程序中变量如果要保证值在下一次运行时仍有效,则必须为static
    static const TickType_t delay = 1000 / portTICK_PERIOD_MS;
 
    //协同程序必须以crSTART(handle)开始
    crSTART(handle);
     
    //协同程序主体
    while(1)
    {
        /* 协同程序工作内容 */
         
        //主动阻塞1000ms,让出CPU使用权
        crDELAY(handle,delay);
    }
     
    //协同程序必须以crEND()结束
    crEND()    
}

使用vCoRoutineSchedule来调度协同程序,调用这个函数时,他会运行可运行的优先级最高的协同程序,当这个协同程序让出CPU时,vCoRoutineSchedule返回。需要不断的调用这个函数来进行协程的调度。

#include <croutine.h>
void vCoRoutineSchedule(void);

使用xCoRoutineCreate来创建一个协程,它的第一个参数是协程函数,第二个参数是协程优先级,可以用同一个协程函数创建多个协程,第三个参数用来区分同一个函数创建的协程。

#include <croutine.h>
BaseType_t xCoRoutineCreate(crCOROUTINE_CODE pxCoRoutineCode, 
                            UBaseType_t uxPriority, 
                            UBaseType_t uxIndex );

下面这个示例使用同一个函数创建了4个协程,协程函数打印uxIndex并阻塞1000ms:

#include <stm32f4xx.h>
#include <FreeRTOS.h>
#include <task.h>
#include <croutine.h>
#include <uart.h>
 
void coTask(CoRoutineHandle_t h,UBaseType_t uxIndex);
void task(void* args);
 
int main()
{
    //配置USART1
    USART1_Config();
    //创建协程
    xCoRoutineCreate(coTask,0,0);
    xCoRoutineCreate(coTask,0,1);
    xCoRoutineCreate(coTask,0,2);
    xCoRoutineCreate(coTask,0,3);
    //创建任务,用于调度协程
    xTaskCreate(task,"task1",configMINIMAL_STACK_SIZE,NULL,1,NULL);
    //启动任务调度器
    vTaskStartScheduler();
}
 
void task(void* args)
{
    while(1)
    {
        //运行优先级最高的协程,该协程让出时,函数返回
        vCoRoutineSchedule();
    }
}
 
 
void coTask(CoRoutineHandle_t handle,UBaseType_t uxIndex)
{
    //如果协程函数希望在阻塞后仍能保存变量的值,那么变量必须是static的
    static const TickType_t delay = 1000 / portTICK_PERIOD_MS;
     
    //协程函数必须以crSTART开始
    crSTART(handle);
     
    while(1)
    {
        //通过串口打印uxIndex
        USART_printf(USART1,"coTask1 : %d\n",uxIndex);
        //在协程中延时1000ms
        crDELAY(handle,delay);
    }
     
    //协程函数必须以crEND结束
    crEND();
     
}

Image

作者: PlanC
2024-12-18 20:03:48+08:00