FreeRTOS系列补充2:重点API函数的应用代码范例(特特特详细)

目录

前言

 动态创建任务函数原型

 动态创建任务函数使用范例

 静态创建函数原型

静态创建任务函数使用范例

任务删除函数原型

任务删除函数使用范例

2、任务挂起和恢复函数

任务挂起函数原型

任务恢复函数(任务中恢复)原型

任务恢复函数(中断中恢复)原型

任务恢复函数(中断中恢复)使用范例

任务恢复和挂起函数总结

3、临界区的代码保护函数

任务级进入和退出临界段函数原型

任务级进入和退出临界段函数使用范例

中断级进入和退出临界段函数原型

中断级进入和退出临界段函数使用范例

4、任务调度器的挂起和恢复

 任务调度器的挂起和恢复函数原型

任务调度器的挂起和恢复函数的使用范例

5、列表

6、任务调度器的开启

开启任务调度器函数原型

7、时间片调度配置

注意:使用时间片调度需把宏 configUSE_TIME_SLICING 和 configUSE_PREEMPTION 置1

8、Freertos任务相关API函数

获取任务优先级的函数原型

获取任务优先级函数优先级的函数使用范例

改变某个任务的任务优先级函数原型

改变某个任务的任务优先级函数原型的使用范例

获取系统中任务数量的API函数原型

获取系统中任务数量的API函数使用范例

获取所有任务状态信息函数原型

获取所有任务状态信息函数原型使用范例

获取单个任务的状态信息原型

获取单个任务的状态信息使用范例

直接获取当前任务的任务句柄函数原型

直接获取当前任务的任务句柄函数使用范例

通过任务名获取任务句柄函数原型

通过任务名获取任务句柄函数使用范例

获取指定任务的任务历史堆栈最小值函数原型

获取指定任务的任务历史堆栈最小值函数使用范例

此函数用于查询某个任务的运行状态原型

此函数用于查询某个任务的运行状态使用范例

用表格的形式获取系统中任务的信息函数原型

用表格的形式获取系统中任务的信息函数使用范例

时间统计API函数原型

时间统计API函数使用流程

9、延时函数(相对延时和绝对延时)

相对延时:

10、队列

队列结构体

结构体中的联合体

当用于队列使用时

当用于互斥信号量和递归互斥信号量时

动态创建队列的API函数原型

动态创建队列的API函数使用范例

往队列中写入消息的API函数原型

三种写入位置

往队列中写入消息的API函数入口参数解析

往队列中写入消息的API函数使用范例

在队列头部读取消息,并根据函数名字不一做调整       

在任务中读取,不删除消息

在中断中读取,不删除消息

在任务中读取,并删除消息

在中断中读取,并删除消息

函数参数解析

函数使用实例

11、信号量

创建二值信号量函数原型

相关宏定义及参数

创建二值信号量函数使用范例

获取二值信号量函数原型

获取二值信号量函数使用实例

释放二值信号量函数原型与参数解析

释放二值信号量函数使用实例

创建(动态)计数型信号量函数原型

创建(动态)计数型信号量函数使用实例

获取信号量当前计数值函数原型

获取信号量当前计数值函数使用示例


前言

其实在网上已经有很多相关的博文了,不过我还是决定自己动手来记录一下。按照之前的经验,需要达到的目的为切题,详细。否则回看的时候不清楚。好多,整理的好累。

并且,在函数开始前我们首先需要知道一下在RTOS中地变量和函数命名风格。

https://blog.csdn.net/xinghuanmeiying/article/details/78180231

上面这个链接地博主写的特别好。理解如下

命名规则
u :代表unsigned。

s :代表short。

c :char。
所以类似uc,us类的变量就是unsigned char,unsigned short,分别对应uint8_t,uint16_t。

x :为用户自定义的数据类型,比如结构体,队列等。
常看到ux开头的函数,就是unsigned且用户自定义的类型。需要注意的是size_t变量前缀也是ux。一般返回值为任务句柄

e :枚举变量

p :指针变量
类似(uint16_t *)变量前缀为pus。

prv :static函数

v: void函数

ux:一般是返回值为无符号整数,变量类为UBaseType_t

 动态创建任务函数原型

BaseType_t xTaskCreate
( 	TaskFunction_t 				pxTaskCode,		/* 指向任务函数的指针 */					
    const char * const 				pcName, 		/* 任务名字,最大长度configMAX_TASK_NAME_LEN */
	const 	configSTACK_DEPTH_TYPE 		usStackDepth, 	/* 任务堆栈大小,注意字为单位 */
	void * const 					pvParameters,	/* 传递给任务函数的参数 */
	UBaseType_t 					uxPriority,		/* 任务优先级,范围:0 ~ configMAX_PRIORITIES - 1 */
	TaskHandle_t * const 			pxCreatedTask 	/* 任务句柄,就是任务的任务控制块 */
)

返回值

描述

pdPASS

任务创建成功

errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY

任务创建失败

 动态创建任务函数使用范例

将宏configSUPPORT_DYNAMIC_ALLOCATION 配置为 1

//任务优先级
#define START_TASK_PRIO		1
//任务堆栈大小	
#define START_STK_SIZE 		128  
//任务句柄
TaskHandle_t StartTask_Handler;
//任务函数
void start_task(void *pvParameters);


	//创建开始任务
    xTaskCreate((TaskFunction_t )start_task,            //任务函数
                (const char*    )"start_task",          //任务名称
                (uint16_t       )START_STK_SIZE,        //任务堆栈大小
                (void*          )NULL,                  //传递给任务函数的参数
                (UBaseType_t    )START_TASK_PRIO,       //任务优先级
                (TaskHandle_t*  )&StartTask_Handler);   //任务句柄     


//开始任务任务函数
void start_task(void *pvParameters)
{
    taskEXIT_CRITICAL();            //退出临界区
    //代码执行逻辑
    taskENTER_CRITICAL();           //进入临界区

}

 静态创建函数原型

TaskHandle_t xTaskCreateStatic(
    TaskFunction_t pxTaskCode,         /* 指向任务函数的指针 */
    const char *const pcName,          /* 任务函数名 */
    const uint32_t ulStackDepth,       /* 任务堆栈大小注意字为单位 */
    void *const pvParameters,          /* 传递的任务函数参数 */
    UBaseType_t uxPriority,            /* 任务优先级 */
    StackType_t *const puxStackBuffer, /* 任务堆栈,一般为数组,由用户分配 */
    StaticTask_t *const pxTaskBuffer   /* 任务控制块指针,由用户分配 */
);

返回值

描述

NULL

用户没有提供相应的内存,任务创建失败

其他值

任务句柄,任务创建成功

静态创建任务函数使用范例

不全,有点多,先放着静态的

#define START_TASK_PRIO 1                   // 任务优先级
#define START_STK_SIZE 128                  // 任务堆栈大小
StackType_t StartTaskStack[START_STK_SIZE]; // 任务堆栈
StaticTask_t StartTaskTCB;                  // 任务控制块
TaskHandle_t StartTask_Handler;             // 任务句柄
void start_task(void *pvParameters);        // 任务函数

// 创建开始任务
StartTask_Handler = xTaskCreateStatic((TaskFunction_t)start_task,     // 任务函数
                                      (const char *)"start_task",     // 任务名称
                                      (uint32_t)START_STK_SIZE,       // 任务堆栈大小
                                      (void *)NULL,                   // 传递给任务函数的参数
                                      (UBaseType_t)START_TASK_PRIO,   // 任务优先级
                                      (StackType_t *)StartTaskStack,  // 任务堆栈
                                      (StaticTask_t *)&StartTaskTCB); // 任务控制块                                           // 开启任务调度

// 开始任务任务函数
void start_task(void *pvParameters)
{
    taskENTER_CRITICAL(); // 进入临界区
    // 创建TASK1任务
    taskEXIT_CRITICAL(); // 退出临界区
}

任务删除函数原型

void vTaskDelete(TaskHandle_t xTaskToDelete);

形参

描述

xTaskToDelete

待删除任务的任务句柄

任务删除函数使用范例

vTaskDelete(Task2Task_Handler);

这里调用这个函数的话,只需要传入需要删除的函数句柄就好了。这里的Task2Task_Handler只是为了进行演示使用的,大家可以根据自己的实际情况调整。以后这种只需要传入单个参数且参数为任务句柄同时无返回值时就不再写使用范例了,大家看到这里应该都是有基础的。

2、任务挂起和恢复函数

任务挂起函数原型

void vTaskSuspend(TaskHandle_t xTaskToSuspend) 

形参

描述

xTaskToSuspend

待挂起任务的任务句柄

此函数用于挂起任务,使用时需将宏 INCLUDE_vTaskSuspend  配置为 1

无论优先级如何,被挂起的任务都将不再被执行,直到任务被恢复 。

注意:当传入的参数为NULL,则代表挂起任务自身(当前正在运行的任务)

任务恢复函数(任务中恢复)原型

void vTaskResume(TaskHandle_t xTaskToResume) 

形参

描述

xTaskToResume

待恢复任务的任务句柄

使用该函数注意宏:INCLUDE_vTaskSuspend必须定义为 1

注意:任务无论被 vTaskSuspend() 挂起多少次,只需在任务中调用  vTakResume() 恢复一次,就可以继续运行。且被恢复的任务会进入就绪态!

任务恢复函数(中断中恢复)原型

BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)  

形参

描述

xTaskToResume

待恢复任务的任务句柄

函数:xTaskResumeFromISR返回值描述如下:

返回值

描述

pdTRUE

任务恢复后需要进行任务切换

pdFALSE

任务恢复后不需要进行任务切换

使用该函数注意宏:INCLUDE_vTaskSuspend INCLUDE_xTaskResumeFromISR 必须定义为 1

该函数专用于中断服务函数中,用于解挂被挂起任务

注意:中断服务程序中要调用freeRTOSAPI函数则中断优先级不能高于FreeRTOS所管理的最高优先级

任务恢复函数(中断中恢复)使用范例

#include <Arduino_FreeRTOS.h>

TaskHandle_t xTaskToResume = NULL;

void MyInterruptHandler(void)
{
    BaseType_t xHigherPriorityTaskWoken = pdFALSE;

    // 尝试从 ISR 中恢复任务,这里注入的参数为函数句柄就可以了
    xHigherPriorityTaskWoken = xTaskResumeFromISR(xTaskToResume);

    // 如果需要,请求上下文切换,因为这个时候被恢复的任务优先级可能比正在执行地任务优先级更高。
    portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}

void setup()
{
    // 初始化任务、中断等
    // 将中断处理函数与相应的中断连接
    attachInterrupt(digitalPinToInterrupt(2), MyInterruptHandler, RISING);
}

void loop()
{
    // Empty. Things are done in tasks.
}

任务恢复和挂起函数总结

3、临界区的代码保护函数

应用场景:FreeRTOS在进入临界段代码的时候需要关闭中断,当处理完临界段代码以后再打开中断

任务级进入和退出临界段函数原型

函数

描述

taskENTER_CRITICAL()

任务级进入临界段

taskEXIT_CRITICAL()

任务级退出临界段

任务级进入和退出临界段函数使用范例

taskENTER_CRITICAL() ;
{
        … …	/* 临界区 */
}
taskEXIT_CRITICAL()	;	

中断级进入和退出临界段函数原型

函数

描述

taskENTER_CRITICAL_FROM_ISR()

中断级进入临界段

taskEXIT_CRITICAL_FROM_ISR()

中断级退出临界段

中断级进入和退出临界段函数使用范例

uint32_t  save_status;
save_status  = taskENTER_CRITICAL_FROM_ISR();
{
        … …	/* 临界区 */
}
taskEXIT_CRITICAL_FROM_ISR(save_status );	

4、任务调度器的挂起和恢复

挂起任务调度器, 调用此函数仅仅只是防止了任务间的资源争夺,中断照样可以响应。挂起调度器的防止,适用于临界区位于任务与任务之间。这样既不会延时中断,又可以做到临界区安全。

 任务调度器的挂起和恢复函数原型

函数

描述

vTaskSuspendAll()

挂起任务调度器

xTaskResumeAll()

恢复任务调度器

任务调度器的挂起和恢复函数的使用范例

vTaskSuspendAll() ;

{

        … …  /* 内容 */

}

xTaskResumeAll()  ; 

5、列表

6、任务调度器的开启

开启任务调度器函数原型

vTaskStartScheduler()

prvStartFirstTask ()   /* 开启第一个任务 */

vPortSVCHandler ()   /* SVC中断服务函数 */

7、时间片调度配置

注意:使用时间片调度需把宏 configUSE_TIME_SLICING configUSE_PREEMPTION 1

8、Freertos任务相关API函数

获取任务优先级的函数原型

UBaseType_t  uxTaskPriorityGet(  const TaskHandle_t xTask  )

此函数用于获取指定任务的任务优先级,使用该函数需将宏 INCLUDE_uxTaskPriorityGet 置 1

形参

描述

       xTask

要查找的任务句柄,NULL代表任务自身

返回值

描述

整数

任务优先级数值

获取任务优先级函数优先级的函数使用范例

  // 创建任务并获取任务句柄
  xTaskCreate(Task1, "Task1", 100, NULL, 1, &xTaskHandle);

  // 获取任务的优先级并输出
  UBaseType_t priority = uxTaskPriorityGet(xTaskHandle);

改变某个任务的任务优先级函数原型

void vTaskPrioritySet( TaskHandle_t xTask , UBaseType_t uxNewPriority )

此函数用于改变某个任务的任务优先级,使用该函数需将宏 INCLUDE_vTaskPrioritySet  为 1

                     xTask

任务句柄,NULL代表任务自身

uxNewPriority

需要设置的任务优先级

改变某个任务的任务优先级函数原型的使用范例

// 定义任务句柄
TaskHandle_t xTask1Handle, xTask2Handle;
 // 创建任务2
xTaskCreate(vTask2, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, &xTask2Handle);
vTaskPrioritySet(xTask2Handle, 3); // 将任务2的优先级设置为3

获取系统中任务数量的API函数原型

UBaseType_t uxTaskGetNumberOfTasks( void )

形参

描述

                     xTask

任务句柄,NULL代表任务自身

uxNewPriority

需要设置的任务优先级

获取系统中任务数量的API函数使用范例

// 获取当前活动任务的数量并输出
  UBaseType_t numTasks = uxTaskGetNumberOfTasks();

获取所有任务状态信息函数原型

UBaseType_t  uxTaskGetSystemState(   TaskStatus_t * const pxTaskStatusArray,
                                      				const UBaseType_t uxArraySize,
                                      				configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime  )

此函数用于获取系统中所有任务的任务状态信息,使用该函数需将宏 configUSE_TRACE_FACILITY 1

形参

描述

xTaskStatusArray

指向TaskStatus_t 结构体数组首地址

uxArraySize

接收信息的数组大小

pulTotalRunTime

系统总运行时间,为NULL 则省略总运行时间值

形参

描述

xTaskStatusArray

指向TaskStatus_t 结构体数组首地址

获取所有任务状态信息函数原型使用范例

#include <FreeRTOS.h>
#include <task.h>

#define TASKS_ARRAY_SIZE 10

TaskHandle_t xTask1Handle, xTask2Handle;

void vTask1(void *pvParameters) {
    // 任务1的代码
    while(1) {
        // 执行任务1的操作
    }
}

void vTask2(void *pvParameters) {
    // 任务2的代码
    while(1) {
        // 执行任务2的操作
    }
}

void main(void) {
    TaskStatus_t xTaskStatusArray[TASKS_ARRAY_SIZE];
    UBaseType_t uxArraySize;

    // 创建任务1
    xTaskCreate(vTask1, "Task 1", configMINIMAL_STACK_SIZE, NULL, 1, &xTask1Handle);

    // 创建任务2
    xTaskCreate(vTask2, "Task 2", configMINIMAL_STACK_SIZE, NULL, 2, &xTask2Handle);

    // 启动任务调度器
    vTaskStartScheduler();

    // 获取系统中所有任务的状态信息
    uxArraySize = uxTaskGetSystemState(xTaskStatusArray, TASKS_ARRAY_SIZE, NULL);

    // 打印任务状态信息
    for (UBaseType_t i = 0; i < uxArraySize; i++) {
        printf("Task Name: %s, Priority: %d, State: %d\n",
               xTaskStatusArray[i].pcTaskName,
               xTaskStatusArray[i].uxCurrentPriority,
               xTaskStatusArray[i].eCurrentState);
    }

    // 任务调度器不会返回,除非发生错误
    for(;;);
}

这里想要提取哪些信息的话需要根据结构体的成员变量改变

typedef struct xTASK_STATUS
{
          TaskHandle_t xHandle; //任务句柄
          const char * pcTaskName; //任务名字
          UBaseType_t xTaskNumber; //任务编号
          eTaskState eCurrentState; //当前任务壮态, eTaskState 是一个枚举类型
          UBaseType_t uxCurrentPriority; //任务当前的优先级
          UBaseType_t uxBasePriority; //任务基础优先级
          uint32_t ulRunTimeCounter;//任务运行的总时间
          StackType_t * pxStackBase; //堆栈基地址
          uint16_t usStackHighWaterMark;//从任务创建以来任务堆栈剩余的最小大小,此
                                        //值如果太小的话说明堆栈有溢出的风险。
} TaskStatus_t;

获取单个任务的状态信息原型

void vTaskGetInfo(
    FTaskHandle_t xTask,
    TaskStatus_t *pxTaskStatus,
    BaseType_t xGetFreeStackSpace,
    eTaskState eState)

形参

描述

xTask

指定获取信息的任务的句柄

pxTaskStatus

接收任务信息的变量

xGetFreeStackSpace

任务栈历史剩余最小值,

当为“pdFALSE 则跳过这个步骤,

当为“pdTRUE”则检查历史剩余最小堆栈

eState

任务状态,可直接赋值,如想获取代入“eInvalid

获取单个任务的状态信息使用范例

    TaskStatus_t xTaskStatus;

    // 创建一个任务
    TaskHandle_t xTaskHandle;
    xTaskCreate(vTaskFunction, "Task", configMINIMAL_STACK_SIZE, NULL, 1, &xTaskHandle);
    // 获取任务的信息
    vTaskGetInfo(xTaskHandle, &xTaskStatus, pdFALSE, eRunning);

    // 打印任务的状态信息
    printf("Task Name: %s\n", xTaskStatus.pcTaskName);
    printf("Task Priority: %d\n", xTaskStatus.uxCurrentPriority);
    printf("Task State: %d\n", xTaskStatus.eCurrentState);

直接获取当前任务的任务句柄函数原型

TaskHandle_t    xTaskGetCurrentTaskHandle( void ) 

此函数用于获取当前任务的任务句柄, 使用该函数需将INCLUDE_xTaskGetCurrentTaskHandle  1

返回值

描述

                      TaskHandle_t

当前任务的任务句柄

直接获取当前任务的任务句柄函数使用范例

     TaskHandle_t xTaskHandle;
// 获取当前任务的句柄
    xTaskHandle = xTaskGetCurrentTaskHandle();

    // 打印当前任务的句柄
    printf("Current Task Handle: %p\n", xTaskHandle);

通过任务名获取任务句柄函数原型

TaskHandle_t xTaskGetHandle(const char * pcNameToQuery); 

通过任务名获取任务句柄函数使用范例

void main(void) {
    TaskHandle_t xTaskHandle;

    // 创建一个任务
    xTaskCreate(vTaskFunction, "Task1", configMINIMAL_STACK_SIZE, NULL, 1, &xTaskHandle);

    // 获取任务句柄
    TaskHandle_t xTaskHandle2 = xTaskGetHandle("Task1");

    // 检查句柄是否有效
    if (xTaskHandle2 != NULL) {
        printf("Task1 handle: %p\n", xTaskHandle2);
    } else {
        printf("Task1 not found!\n");
    }

    for (;;) {
        // 主循环
    }
}

获取指定任务的任务历史堆栈最小值函数原型

UBaseType_t    uxTaskGetStackHighWaterMark( TaskHandle_t  xTask )

使用该函数需将宏 INCLUDE_uxTaskGetStackHighWaterMark 1

形参

描述

              xTask

                       任务句柄

返回值

描述

    UBaseType_t

                  任务栈的历史剩余最小值

获取指定任务的任务历史堆栈最小值函数使用范例

    // 在这里检查任务堆栈的高水位标记
    UBaseType_t uxHighWaterMark;
    
    uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL ); // 传入NULL表示获取当前任务的堆栈高水位标记
    
    // 输出高水位标记到串口或者日志
    printf( "Task stack high water mark: %u bytes\n", uxHighWaterMark );

此函数用于查询某个任务的运行状态原型

需将宏 INCLUDE_eTaskGetState 置一

eTaskState    eTaskGetState(TaskHandle_t xTask)

形参

描述

              xTask

        待获取状态任务的任务句柄

返回值

描述

     eTaskState

                                任务状态

eTaskState可能的参数

typedef enum
{   
	eRunning = 0,	/* 运行态 */ 
	eReady		/* 就绪态 */ 
	eBlocked, 		/* 阻塞态 */ 
	eSuspended, 	/* 挂起态 */ 
	eDeleted, 		/* 任务被删除 */ 
	eInvalid		/* 无效 */ 
} eTaskState;

此函数用于查询某个任务的运行状态使用范例

  // 获取任务状态
    eTaskState taskState = eTaskGetState(xTaskHandle);
    
    // 根据任务状态执行相应的操作
    switch(taskState)
    {
        case eRunning:
            // 任务正在运行
            break;
        case eReady:
            // 任务处于就绪状态
            break;
        case eBlocked:
            // 任务被阻塞
            break;
        case eSuspended:
            // 任务被挂起
            break;
        case eDeleted:
            // 任务已被删除
            break;
        default:
            // 未知状态
            break;
    }

用表格的形式获取系统中任务的信息函数原型

void   vTaskList(char * pcWriteBuffer)

宏 configUSE_TRACE_FACILITYconfigUSE_STATS_FORMATTING_FUNCTIONS 1

形参

描述

        pcWriteBuffer

        接收任务信息的缓存指针

表格如下

Name      : 创建任务的时候给任务分配的名字。
State      : 任务的壮态信息, B 是阻塞态, R 是就绪态, S 是挂起态, D 是删除态
Priority  :任务优先级。
Stack      : 任务堆栈的“高水位线”,就是堆栈历史最小剩余大小。
Num      : 任务编号,这个编号是唯一的,当多个任务使用同一个任务名的时候可以通过此编号来做区分。

用表格的形式获取系统中任务的信息函数使用范例

    // 获取任务列表信息
    char taskListBuffer[1024]; // 用于保存任务列表信息的缓冲区
    vTaskList(taskListBuffer);

    // 打印任务列表信息
    printf("Task List:\n%s", taskListBuffer);

时间统计API函数原型

Void    vTaskGetRunTimeStats( char * pcWriteBuffer ) 

此函数用于统计任务的运行时间信息,使用此函数需将宏 configGENERATE_RUN_TIME_STAT configUSE_STATS_FORMATTING_FUNCTIONS 1

形参

描述

       pcWriteBuffer

             接收任务运行时间信息的缓存指针

时间统计API函数使用流程

1、将宏 configGENERATE_RUN_TIME_STATS 1

2、将宏 configUSE_STATS_FORMATTING_FUNCTIONS  1

3、当将此宏 configGENERATE_RUN_TIME_STAT  1之后,还需要实现2个宏定义:

portCONFIGURE_TIMER_FOR_RUNTIME_STATE() :用于初始化用于配置任务运行时间统计的时基定时器;

注意:这个时基定时器的计时精度需高于系统时钟节拍精度的10100

portGET_RUN_TIME_COUNTER_VALUE():用于获取该功能时基硬件定时器计数的计数值 。

9、延时函数(相对延时和绝对延时)

函数

描述

vTaskDelay()

相对延时

xTaskDelayUntil()

绝对延时

相对延时:

指每次延时都是从执行函数vTaskDelay()开始,直到延时指定的时间结束

绝对延时:

指将整个任务的运行周期看成一个整体,适用于需要按照一定频率运行的任务

10、队列

队列结构体

typedef struct QueueDefinition 
{
    int8_t * pcHead					/* 存储区域的起始地址 */
    int8_t * pcWriteTo;        				/* 下一个写入的位置 */
    union
    {
    QueuePointers_t     xQueue; 
	SemaphoreData_t  xSemaphore; 
    } u ;
    List_t xTasksWaitingToSend; 			/* 等待发送列表 */
    List_t xTasksWaitingToReceive;			/* 等待接收列表 */
    volatile UBaseType_t uxMessagesWaiting; 	/* 非空闲队列项目的数量 */
    UBaseType_t uxLength;			/* 队列长度 */
    UBaseType_t uxItemSize;                 		/* 队列项目的大小 */
    volatile int8_t cRxLock; 				/* 读取上锁计数器 */
    volatile int8_t cTxLock;			/* 写入上锁计数器 */
   /* 其他的一些条件编译 */
} xQUEUE;

结构体中的联合体

当用于队列使用时

typedef struct QueuePointers
{
     int8_t * pcTail; 				/* 存储区的结束地址 */
     int8_t * pcReadFrom;			/* 最后一个读取队列的地址 */
} QueuePointers_t;

当用于互斥信号量和递归互斥信号量时

typedef struct SemaphoreData
{
    TaskHandle_t xMutexHolder;		/* 互斥信号量持有者 */
    UBaseType_t uxRecuarsiveCallCount;	/* 递归互斥信号量的获取计数器 */
} SemaphoreData_t;

动态创建队列的API函数原型

#define xQueueCreate (  uxQueueLength,   uxItemSize  )   						 \			a			
	   xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ), (queueQUEUE_TYPE_BASE )) 

形参

描述

uxQueueLength

队列长度

uxItemSize

队列项目的大小

返回值

描述

NULL

队列创建失败

其他值

队列创建成功,返回队列句柄

动态创建队列的API函数使用范例

#include <queue.h> // 假设宏定义的头文件是这个

// 在某个函数或全局范围内调用 xQueueCreate 宏来创建队列
void createQueueExample() {
    // 假设要创建一个长度为 10,每个项目大小为 sizeof(int) 的队列
    QueueHandle_t myQueue = xQueueCreate(10, sizeof(int));

    if (myQueue == NULL) {
        // 队列创建失败,进行错误处理
        printf("Failed to create queue\n");
    } else {
        // 队列创建成功,进行其他操作
        printf("Queue created successfully\n");
    }
}

前面说 FreeRTOS 基于队列实现了多种功能,每一种功能对应一种队列类型,队列类型的 queue.h 文件中有定义:

#define queueQUEUE_TYPE_BASE                  			( ( uint8_t ) 0U )	/* 队列 */
#define queueQUEUE_TYPE_SET                  			( ( uint8_t ) 0U )	/* 队列集 */
#define queueQUEUE_TYPE_MUTEX                 			( ( uint8_t ) 1U )	/* 互斥信号量 */
#define queueQUEUE_TYPE_COUNTING_SEMAPHORE    	( ( uint8_t ) 2U )	/* 计数型信号量 */
#define queueQUEUE_TYPE_BINARY_SEMAPHORE     	( ( uint8_t ) 3U )	/* 二值信号量 */
#define queueQUEUE_TYPE_RECURSIVE_MUTEX       		( ( uint8_t ) 4U )	/* 递归互斥信号量 */

往队列中写入消息的API函数原型

//默认发送到尾部
#define  xQueueSend(  xQueue,   pvItemToQueue,   xTicksToWait  )	 					\    
	    xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )

#define  xQueueSendToBack(  xQueue,   pvItemToQueue,   xTicksToWait  )					 \    
	    xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )

#define  xQueueSendToFront(  xQueue,   pvItemToQueue,   xTicksToWait  ) 				
	    xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_FRONT )

#define  xQueueOverwrite(  xQueue,   pvItemToQueue  ) 								\    
	    xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), 0, queueOVERWRITE )

其实本质上都是调用同一个函数xQueueGenericSend( ) ,只是指定了不同的写入位置

三种写入位置

#define queueSEND_TO_BACK     	( ( BaseType_t ) 0 )		/* 写入队列尾部 */
#define queueSEND_TO_FRONT      ( ( BaseType_t ) 1 )		/* 写入队列头部 */
#define queueOVERWRITE           ( ( BaseType_t ) 2 )		/* 覆写队列*/

注意:覆写方式写入队列,只有在队列的队列长度为 1 时,才能够使用

往队列中写入消息的API函数入口参数解析

BaseType_t     xQueueGenericSend(  QueueHandle_t 	xQueue,
					            const void * const 	pvItemToQueue,
				                TickType_t 		xTicksToWait,
					            const BaseType_t 	xCopyPosition   ); 

形参

描述

xQueue

待写入的队列

pvItemToQueue

待写入消息的地址(指针变量)

xTicksToWait

阻塞超时时间

xCopyPosition

写入的位置

返回值

描述

pdTRUE

队列写入成功

errQUEUE_FULL

队列写入失败

往队列中写入消息的API函数使用范例

#include <stdio.h>
#include <stdint.h>
#include "FreeRTOS.h"
#include "queue.h"

#define QUEUE_LENGTH 5

void sender_task(void *pvParameters) {
    QueueHandle_t queue = (QueueHandle_t)pvParameters;

    // 要发送的数据
    uint32_t data_to_send = 123;

    // 发送数据到队列
    BaseType_t result = xQueueGenericSend(queue, &data_to_send, portMAX_DELAY, queueSEND_TO_BACK);

    if (result == errQUEUE_FULL) {
        printf("Data sent to queue: %u\n", data_to_send);
    } else {
        printf("Failed to send data to queue\n");
    }

    vTaskDelete(NULL);
}

在队列头部读取消息,并根据函数名字不一做调整       

在任务中读取,不删除消息

BaseType_t    xQueuePeek( QueueHandle_t   xQueue,  void *   const pvBuffer,  TickType_t   xTicksToWait )

在中断中读取,不删除消息

BaseType_t    xQueueReceiveFromISR( QueueHandle_t   xQueue,  void *   const pvBuffer,  TickType_t   xTicksToWait )

在任务中读取,并删除消息

BaseType_t    xQueueReceive( QueueHandle_t   xQueue,  void *   const pvBuffer,  TickType_t   xTicksToWait )

在中断中读取,并删除消息

BaseType_t    xQueueReceiveFromISR( QueueHandle_t   xQueue,  void *   const pvBuffer,  TickType_t   xTicksToWait )

函数参数解析

形参

描述

xQueue

待读取的队列

pvBuffer

信息读取缓冲区

xTicksToWait

阻塞超时时间

返回值

描述

pdTRUE

读取成功

pdFALSE

读取失败

函数使用实例

#include <stdio.h>
#include "FreeRTOS.h"
#include "queue.h"

void peek_task(void *pvParameters) {
    QueueHandle_t queue = (QueueHandle_t)pvParameters;

    // 缓冲区用于存储查看到的数据
    uint32_t peeked_data;

    // 查看队列中的下一个可用项
    BaseType_t result = xQueuePeek(queue, &peeked_data, portMAX_DELAY);

    if (result == pdPASS) {
        printf("Next item in queue: %u\n", peeked_data);
    } else {
        printf("Failed to peek into queue\n");
    }

    vTaskDelete(NULL);
}

int main() {
    // 创建一个队列
    QueueHandle_t myQueue = xQueueCreate(5, sizeof(uint32_t));

    if (myQueue == NULL) {
        printf("Failed to create queue\n");
        return 1;
    }

    // 向队列中发送一些数据
    uint32_t data_to_send = 123;
    xQueueSend(myQueue, &data_to_send, portMAX_DELAY);

    // 创建查看任务
    xTaskCreate(peek_task, "Peek Task", configMINIMAL_STACK_SIZE, (void *)myQueue, tskIDLE_PRIORITY + 1, NULL);

    // 启动调度器
    vTaskStartScheduler();

    // 不应该运行到这里
    return 0;
}

11、信号量

创建二值信号量函数原型

SemaphoreHandle_t   xSemaphoreCreateBinary( void ) 

相关宏定义及参数

 #define   xSemaphoreCreateBinary( )   						\
 xQueueGenericCreate( 1 ,   semSEMAPHORE_QUEUE_ITEM_LENGTH  ,   queueQUEUE_TYPE_BINARY_SEMAPHORE )
#define  semSEMAPHORE_QUEUE_ITEM_LENGTH      ( ( uint8_t ) 0U )

#define queueQUEUE_TYPE_BASE                  	( ( uint8_t ) 0U )	/* 队列 */
#define queueQUEUE_TYPE_SET                  	( ( uint8_t ) 0U )	/* 队列集 */
#define queueQUEUE_TYPE_MUTEX                 	
#define queueQUEUE_TYPE_COUNTING_SEMAPHORE    	( ( uint8_t ) 2U )	/* 计数型信号量 */
#define queueQUEUE_TYPE_BINARY_SEMAPHORE     	( ( uint8_t ) 3U )	/* 二值信号量 */
#define queueQUEUE_TYPE_RECURSIVE_MUTEX       	( ( uint8_t ) 4U )	/* 递归互斥信号量 */

返回值

描述

NULL

创建失败

其他值

创建成功返回二值信号量的句柄

创建二值信号量函数使用范例

// 定义一个二进制信号量句柄
SemaphoreHandle_t binarySemaphore;
// 创建二进制信号量
binarySemaphore = xSemaphoreCreateBinary();

获取二值信号量函数原型

BaseType_t   xSemaphoreTake( xSemaphore, xBlockTime ) 

形参

描述

xSemaphore

要获取的信号量句柄

xBlockTime

阻塞时间

返回值

描述

pdTRUE

获取信号量成功

pdFALSE

超时,获取信号量失败

获取二值信号量函数使用实例

SemaphoreHandle_t binarySemaphore;

void someTask(void *pvParameters) {
    // 尝试获取二值信号量,等待时间为100个时钟节拍
    BaseType_t result = xSemaphoreTake(binarySemaphore, 100);
    
    if (result == pdPASS) {
        // 成功获取到了信号量
    } else {
        // 未能获取到信号量,超时或其他原因
    }
}

释放二值信号量函数原型与参数解析

BaseType_t   xSemaphoreGive( xSemaphore ) 
#define   xSemaphoreGive (  xSemaphore  )    						\
xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore )  ,   NULL  ,   semGIVE_BLOCK_TIME  ,   queueSEND_TO_BACK )
#define   semGIVE_BLOCK_TIME                  ( ( TickType_t ) 0U )

形参

描述

xSemaphore

要释放的信号量句柄

返回值

描述

pdTRUE

获取信号量成功

pdFALSE

超时,获取信号量失败

释放二值信号量函数使用实例

BaseType_t giveResult = xSemaphoreGive(binarySemaphore);
if (giveResult == pdPASS) {
    // 释放成功
} else {
    // 释放失败,进行错误处理
}

创建(动态)计数型信号量函数原型

#define 	xSemaphoreCreateCounting(  uxMaxCount  ,  uxInitialCount  )   		\		
xQueueCreateCountingSemaphore( (  uxMaxCount  ) , (  uxInitialCount  ) ) 
SemaphoreHandle_t xQueueCreateCountingSemaphore(const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount);

此函数用于创建一个计数型信号量 。

形参

描述

uxMaxCount

计数值的最大值限定

uxInitialCount

计数值的初始值

返回值

描述

NULL

创建失败

其他值

创建成功返回计数型信号量的句柄

创建(动态)计数型信号量函数使用实例

SemaphoreHandle_t countingSemaphore;

void someFunction(void) {
    // 创建一个最大计数值为5,初始计数值为0的计数信号量
    countingSemaphore = xSemaphoreCreateCounting(5, 0);
    
    if (countingSemaphore != NULL) {
        // 计数信号量创建成功
    } else {
        // 计数信号量创建失败
    }
}

获取信号量当前计数值函数原型

UBaseType_t uxSemaphoreGetCount(QueueHandle_t xQueue);

实际上是调用了 uxQueueMessagesWaiting() 函数

形参

描述

xSemaphore

信号量句柄

返回值

描述

NULL

创建失败

其他值

创建成功返回计数型信号量的句柄

获取信号量当前计数值函数使用示例

SemaphoreHandle_t mySemaphore;

void someFunction(void) {
    // 创建一个二进制信号量
    mySemaphore = xSemaphoreCreateBinary();
    
    // 获取信号量的计数值
    if (mySemaphore != NULL) {
        UBaseType_t count = uxSemaphoreGetCount(mySemaphore);
        // 此时 count 应该为 0(如果是二进制信号量)
    }
}

  • 31
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值