目录
基础任务相关函数
动态任务创建函数:
使用前将宏configSUPPORT_DYNAMIC_ALLOCATION 配置为 1
BaseType_t xTaskCreate(
TaskFunction_t pxTaskCode,
const char * const pcName,
const configSTACK_DEPTH_TYPE usStackDepth,
void * const pvParameters,
UBaseType_t uxPriority,
TaskHandle_t * const pxCreatedTask
)
参数:
pxTaskCode /* 指向任务函数的指针 */
pcName /* 任务名字,最大长度configMAX_TASK_NAME_LEN */
usStackDepth, /* 任务堆栈大小,注意字为单位 */
pvParameters, /* 传递给任务函数的参数 */
uxPriority /*任务优先级,范围:0 ~ configMAX_PRIORITIES - 1
pxCreatedTask /* 任务句柄,就是任务的任务控制块 */
返回值:
成功:pdPASS
失败:errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY
静态创建任务函数:
使用前需将宏configSUPPORT_STATIC_ALLOCATION 配置为 1
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 );
参数:
pxTaskCode, /* 指向任务函数的指针 */
pcName, /* 任务函数名 */
ulStackDepth, /* 任务堆栈大小注意字为单位 */
pvParameters, /* 传递的任务函数参数 */
uxPriority, /* 任务优先级 */
puxStackBuffer, /* 任务堆栈,一般为数组,由用户分配
pxTaskBuffer /* 任务控制块指针,由用户分配 */
返回值:
成功:任务句柄
失败:NULL
还需实现两个接口函数:
/*空闲任务内存配置*/
StaticTask_t idle_task_tcb;
StackType_t idle_task_stack[configMINIMAL_STACK_SIZE];
/*软件定时器内存配置*/
StaticTask_t timer_task_tcb;
StackType_t timer_task_stack[configTIMER_TASK_STACK_DEPTH];
void vApplicationGetIdleTaskMemory(
StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
uint32_t * pulIdleTaskStackSize )
{
* ppxIdleTaskTCBBuffer = &idle_task_tcb;
* ppxIdleTaskStackBuffer = idle_task_stack;
* pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}
void vApplicationGetTimerTaskMemory(
StaticTask_t ** ppxTimerTaskTCBBuffer,
StackType_t ** ppxTimerTaskStackBuffer,
uint32_t * pulTimerTaskStackSize )
{
* ppxTimerTaskTCBBuffer = &timer_task_tcb;
* ppxTimerTaskStackBuffer = timer_task_stack;
* pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}
静态创建任务函数示例:
#define START_TASK_PRIO 1
#define START_SIZE 128
TaskHandle_t start_task_handle;
StackType_t start_task_stack[START_SIZE];
StaticTask_t start_task_tcb;#define TASK1_PRIO 2
#define TASK1_SIZE 50
TaskHandle_t task1_handle;
StackType_t task1_stack[TASK1_SIZE];
StaticTask_t task1_tcb;#define TASK2_PRIO 3
#define TASK2_SIZE 50
TaskHandle_t task2_handle;
StackType_t task2_stack[TASK2_SIZE];
StaticTask_t task2_tcb;void freertos_dome(void);
void start_task(void *pvParameters);
void task1(void *pvParameters);
void task2(void *pvParameters);
//空闲任务内存配置
StaticTask_t idle_task_tcb;
StackType_t idle_task_stack[configMINIMAL_STACK_SIZE];
//软件定时器内存配置
StaticTask_t timer_task_tcb;
StackType_t timer_task_stack[configTIMER_TASK_STACK_DEPTH];//空闲任务内存分配
void vApplicationGetIdleTaskMemory(StaticTask_t ** ppxIdleTaskTCBBuffer,
StackType_t ** ppxIdleTaskStackBuffer,
uint32_t * pulIdleTaskStackSize )
{
* ppxIdleTaskTCBBuffer = &idle_task_tcb;
* ppxIdleTaskStackBuffer = idle_task_stack;
* pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
}
//软件定时器内存分配
void vApplicationGetTimerTaskMemory( StaticTask_t ** ppxTimerTaskTCBBuffer,
StackType_t ** ppxTimerTaskStackBuffer,
uint32_t * pulTimerTaskStackSize )
{
* ppxTimerTaskTCBBuffer = &timer_task_tcb;
* ppxTimerTaskStackBuffer = timer_task_stack;
* pulTimerTaskStackSize = configTIMER_TASK_STACK_DEPTH;
}
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);//设置系统中断优先级分组4
delay_init(); //延时函数初始化
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
freertos_dome();
}//开始任务任务函数
void freertos_dome(void)
{
start_task_handle = xTaskCreateStatic(
(TaskFunction_t ) start_task,
(char * ) "start_task",
(uint32_t ) START_SIZE,
(void * ) NULL,
(UBaseType_t ) START_TASK_PRIO,
(StackType_t * ) start_task_stack,
(StaticTask_t * ) &start_task_tcb
);
vTaskStartScheduler(); //开启任务调度
}
void start_task(void *pvParameters)
{
taskENTER_CRITICAL(); //进入临界区
task1_handle = xTaskCreateStatic( (TaskFunction_t ) task1,
(char * ) "task1",
(uint32_t ) TASK1_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK1_PRIO,
(StackType_t * ) task1_stack,
(StaticTask_t * ) &task1_tcb
);
task2_handle = xTaskCreateStatic( (TaskFunction_t ) task2,
(char * ) "task2",
(uint32_t ) TASK2_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK2_PRIO,
(StackType_t * ) task2_stack,
(StaticTask_t * ) &task2_tcb
);
task3_handle = xTaskCreateStatic( (TaskFunction_t ) task3,
(char * ) "task3",
(uint32_t ) TASK3_SIZE,
(void * ) NULL,
(UBaseType_t ) TASK3_PRIO,
(StackType_t * ) task3_stack,
(StaticTask_t * ) &task3_tcb
);
vTaskDelete(start_task_handle);
taskEXIT_CRITICAL(); //退出临界区
}
//实现LED0每500ms反转一次
void task1(void *pvParameters)
{
while(1)
{
printf("-----task1正在运行-----\n");
LED0 = 0;
vTaskDelay(200);
LED0 = 1;
vTaskDelay(200);
}
}
//实现LED1每800ms反转一次
void task2(void *pvParameters)
{
while(1)
{
printf("-----task2正在运行-----\n");
LED1 = 0;
vTaskDelay(800);
LED1 = 1;
vTaskDelay(800);
}
}
任务删除函数
使用删除任务函数,需将宏INCLUDE_vTaskDelete 配置为 1
void vTaskDelete(TaskHandle_t xTaskToDelete);
参数:
xTaskToDelete /*待删除任务的任务句柄*/
传NULL表示删除当前任务
返回值:无
任务挂起函数
此函数用于挂起任务,使用时需将宏 INCLUDE_vTaskSuspend 配置为 1。
void vTaskSuspend(TaskHandle_t xTaskToSuspend)
参数:
xTaskToSuspend 待挂起任务的任务句柄
任务恢复函数(任务中恢复)
使用该函数注意宏:INCLUDE_vTaskSuspend必须定义为 1
void vTaskResume(TaskHandle_t xTaskToResume)
参数:
xTaskToResume 待恢复任务的任务句柄
描述:
注意:任务无论被 vTaskSuspend() 挂起多少次,只需在任务中调用 vTakResume() 恢复一次,就可以继续运行。且被恢复的任务会进入就绪态!
任务恢复函数(中断中恢复)
使用该函数注意宏:INCLUDE_vTaskSuspend 和 INCLUDE_xTaskResumeFromISR 必须定义为 1
BaseType_t xTaskResumeFromISR(TaskHandle_t xTaskToResume)
参数:
xTaskToResume 待恢复任务的任务句柄
返回值: 成功:pdTRUE
失败:pdFLASE
描述:
该函数专用于中断服务函数中,用于解挂被挂起任务
注意:中断服务程序中要调用freeRTOS的API函数则中断优先级不能高于FreeRTOS所管理的最高优先级
中断开启函数
portENABLE_INTERRUPTS ()
参数:无
返回值:无
描述:本质是一个宏定义,具体实现通过操控BASEPRI寄存器实现
中断关闭函数
portDISABLE_INTERRUPTS()
参数:无
返回值:无
描述:本质是一个宏定义,具体实现通过操控BASEPRI寄存器实现
临界段代码保护函数
- taskENTER_CRITICAL() 任务级进入临界段
- taskEXIT_CRITICAL() 任务级退出临界段
- taskENTER_CRITICAL_FROM_ISR() 中断级进入临界段
- taskEXIT_CRITICAL_FROM_ISR() 中断级退出临界段
任务调度器的挂起和恢复
vTaskSuspendAll() 挂起任务调度器
xTaskResumeAll() 恢复任务调度器
列表和列表项
API函数:
函数 | 描述 |
vListInitialise() | 初始化列表 |
vListInitialiseItem() | 初始化列表项 |
vListInsertEnd() | 列表末尾插入列表项 |
vListInsert() | 列表插入列表项 |
uxListRemove() | 列表移除列表项 |
使用示例:
List_t List;
ListItem_t ListItem1;
ListItem_t ListItem2;
ListItem_t ListItem3;
void List_Task(void *p)
{
vListInitialise(&List);
vListInitialiseItem(&ListItem1);
vListInitialiseItem(&ListItem2);
vListInitialiseItem(&ListItem3);
printf("/***********列表和列表项初始化地址********\r/\n");
printf("List %#x\r\n",(int)&List);
printf("ListItem1 %#x\r\n",(int)&ListItem1);
printf("ListItem2 %#x\r\n",(int)&ListItem2);
printf("ListItem3 %#x\r\n",(int)&ListItem3);
printf("/******************结束**********//\r\n");
vListInsert(&List,&ListItem1);
printf("/*************添加ListItem1****************//\r\n");
printf("/**************Next*********//\r\n");
printf("List->xListEnd->pxNext %#x\r\n",(int)(List.xListEnd.pxNext));
printf("ListItem1->pxNext %#x\r\n",(int)(ListItem1.pxNext));
printf("/***************pxPrevious*********//\r\n");
printf("List->xListEnd->pxPrevious %#x\r\n",(int)(List.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious %#x\r\n",(int)(ListItem1.pxPrevious));
vListInsert(&List,&ListItem2);
printf("/************添加ListItem2************//\r\n");
printf("/*******************Next************//\r\n");
printf("List->xListEnd->pxNext %#x\r\n",(int)(List.xListEnd.pxNext));
printf("ListItem1->pxNext %#x\r\n",(int)(ListItem1.pxNext));
printf("ListItem2->pxNext %#x\r\n",(int)(ListItem2.pxNext));
printf("/****************pxPrevious***********//\r\n");
printf("List->xListEnd->pxPrevious %#x\r\n",(int)(List.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious %#x\r\n",(int)(ListItem1.pxPrevious));
printf("ListItem2->pxPrevious %#x\r\n",(int)(ListItem2.pxPrevious));
vListInsert(&List,&ListItem3);
printf("/**************添加ListItem3**************//\r\n");
printf("/*********************Next***************//\r\n");
printf("List->xListEnd->pxNext %#x\r\n",(int)(List.xListEnd.pxNext));
printf("ListItem1->pxNext %#x\r\n",(int)(ListItem1.pxNext));
printf("ListItem2->pxNext %#x\r\n",(int)(ListItem2.pxNext));
printf("ListItem3->pxNext %#x\r\n",(int)(ListItem3.pxNext));
printf("/*****************pxPrevious********//\r\n");
printf("List->xListEnd->pxPrevious %#x\r\n",(int)(List.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious %#x\r\n",(int)(ListItem1.pxPrevious));
printf("ListItem2->pxPrevious %#x\r\n",(int)(ListItem2.pxPrevious));
printf("ListItem3->pxPrevious %#x\r\n",(int)(ListItem3.pxPrevious));
uxListRemove(&ListItem2);
printf("/**************删除ListItem2*******//\r\n");
printf("/**************Next********//\r\n");
printf("List->xListEnd->pxNext %#x\r\n",(int)(List.xListEnd.pxNext));
printf("ListItem1->pxNext %#x\r\n",(int)(ListItem1.pxNext));
printf("ListItem3->pxNext %#x\r\n",(int)(ListItem3.pxNext));
printf("/**************pxPrevious**********//\r\n");
printf("List->xListEnd->pxPrevious %#x\r\n",(int)(List.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious %#x\r\n",(int)(ListItem1.pxPrevious));
printf("ListItem3->pxPrevious %#x\r\n",(int)(ListItem3.pxPrevious));
vListInsertEnd(&List,&ListItem2);
printf("/**************在末尾项添加ListItem2*************//\r\n");
printf("/**************Next*************//\r\n");
printf("List->xListEnd->pxNext %#x\r\n",(int)(List.xListEnd.pxNext));
printf("ListItem1->pxNext %#x\r\n",(int)(ListItem1.pxNext));
printf("ListItem3->pxNext %#x\r\n",(int)(ListItem3.pxNext));
printf("ListItem2->pxNext %#x\r\n",(int)(ListItem2.pxNext));
printf("/***************pxPrevious*****************//\r\n");
printf("List->xListEnd->pxPrevious %#x\r\n",(int)(List.xListEnd.pxPrevious));
printf("ListItem1->pxPrevious %#x\r\n",(int)(ListItem1.pxPrevious));
printf("ListItem3->pxPrevious %#x\r\n",(int)(ListItem3.pxPrevious));
printf("ListItem2->pxPrevious %#x\r\n",(int)(ListItem2.pxPrevious));
while(1)
{
}
}
-
任务状态查询API函数介绍
获取任务优先级
此函数用于获取指定任务的任务优先级,使用该函数需将宏 INCLUDE_uxTaskPriorityGet 置 1
UBaseType_t uxTaskPriorityGet( const TaskHandle_t xTask )
参数:
xTask 要查找的任务句柄,NULL代表任务自身
返回值:
整数 任务优先级数值
设置任务优先级
此函数用于改变某个任务的任务优先级,使用该函数需将宏 INCLUDE_vTaskPrioritySet 为 1
void vTaskPrioritySet( TaskHandle_t xTask , UBaseType_t uxNewPriority )
参数:
xTask 任务句柄,NULL代表任务自身
uxNewPriority 需要设置的任务优先级
获取系统中任务的数量
此函数用于获取系统中任务的任务数量
UBaseType_t uxTaskGetNumberOfTasks( void )
返回值:
整型 系统中任务的数量
获取所有任务状态信息
此函数用于获取系统中所有任务的任务状态信息,使用该函数需将宏 configUSE_TRACE_FACILITY 置 1
UBaseType_t uxTaskGetSystemState(
TaskStatus_t * const pxTaskStatusArray,
const UBaseType_t uxArraySize,
configRUN_TIME_COUNTER_TYPE * const pulTotalRunTime )
参数:
pxTaskStatusArray 指向TaskStatus_t 结构体数组首地址
uxArraySize 接收信息的数组大小
pulTotalRunTime 系统总运行时间,为NULL 则省略总运行时间值
返回值:
整型 获取信息的任务数量
获取指定单个的任务信息
函数用于获取指定的单个任务的状态信息,使用该函数需将宏 configUSE_TRACE_FACILITY 置 1
void vTaskGetInfo( TaskHandle_t xTask,
TaskStatus_t * pxTaskStatus,
BaseType_t xGetFreeStackSpace,
eTaskState eState )参数:
xTask 指定获取信息的任务的句柄
pxTaskStatus 接收任务信息的变量
xGetFreeStackSpace
任务栈历史剩余最小值,
当为“pdFALSE” 则跳过这个步骤,
当为“pdTRUE”则检查历史剩余最小堆栈
eState 任务状态,可直接赋值,如想获取代入“eInvalid”
typedef enum
{
eRunning = 0, /* 运行态 */
eReady /* 就绪态 */
eBlocked, /* 阻塞态 */
eSuspended, /* 挂起态 */
eDeleted, /* 任务被删除 */
eInvalid /* 无效 */
} eTaskState;
获取当前任务的任务句柄
此函数用于获取当前任务的任务句柄, 使用该函数需将宏 INCLUDE_xTaskGetCurrentTaskHandle 置 1
TaskHandle_t xTaskGetCurrentTaskHandle( void )
返回值:
当前任务的任务句柄
根据任务名获取该任务的任务句柄
此函数用于通过任务名获取任务句柄 , 使用该函数需将宏 INCLUDE_xTaskGetHandle 置 1
TaskHandle_t xTaskGetHandle(const char * pcNameToQuery);
参数:
pcNameToQuery 任务名返回值:
任务的任务句柄
获取任务的任务栈历史剩余最小值
此函数用于获取指定任务的任务栈历史最小剩余堆栈;使用该函数需将宏 INCLUDE_uxTaskGetStackHighWaterMark 置 1
UBaseType_t uxTaskGetStackHighWaterMark( TaskHandle_t xTask )
参数:
xTask 任务句柄
返回值:
任务栈的历史剩余最小值
获取任务状态
此函数用于查询某个任务的运行状态,使用此函数需将宏 INCLUDE_eTaskGetState 置1
eTaskState eTaskGetState(TaskHandle_t xTask)
参数:
xTask 任务句柄返回值:
eTaskState 任务当前状态
typedef enum
{
eRunning = 0, /* 运行态 */
eReady /* 就绪态 */
eBlocked, /* 阻塞态 */
eSuspended, /* 挂起态 */
eDeleted, /* 任务被删除 */
eInvalid /* 无效 */
} eTaskState;
以“表格”形式获取所有任务的信息
此函数用于以“表格”的形式获取系统中任务的信息 ;使用此函数需将宏 configUSE_TRACE_FACILITY 和configUSE_STATS_FORMATTING_FUNCTIONS 置1
void vTaskList(char * pcWriteBuffer)
参数:
pcWriteBuffer 接收任务信息的缓存指针
获取任务的运行时间
使用示例:
char task_buff[500];
/* 任务二,实现任务状态查询API函数使用 */
void task2( void * pvParameters )
{
UBaseType_t priority_num = 0;
UBaseType_t task_num = 0;
UBaseType_t task_num2 = 0;
TaskStatus_t * status_array = 0;
TaskStatus_t * status_array2 = 0;
TaskHandle_t task_handle = 0;
UBaseType_t task_stack_min = 0;
eTaskState state = 0;
uint8_t i = 0;
/*改变/设置任务优先级*/
vTaskPrioritySet( task2_handler,4 );
/*获取任务优先级*/
priority_num = uxTaskPriorityGet( NULL );
printf("task2任务优先级为%ld\r\n",priority_num);
/*获取系统中任务数量*/
task_num = uxTaskGetNumberOfTasks();
printf("任务数量:%ld\r\n",task_num);
/*获取所有任务状态信息*/
status_array = mymalloc(SRAMIN,(sizeof(TaskStatus_t) * task_num));
task_num2 = uxTaskGetSystemState( status_array,task_num,NULL);
printf("任务名\t\t任务优先级\t任务编号\r\n");
for(i = 0; i < task_num2; i++)
{
printf("%s\t\t%ld\t%ld\r\n",
status_array[i].pcTaskName,
status_array[i].uxCurrentPriority,
status_array[i].xTaskNumber);
}
/*获取指定单个的任务信息*/
status_array2 = mymalloc(SRAMIN,sizeof(TaskStatus_t));
vTaskGetInfo( task2_handler,status_array2,pdTRUE,eInvalid);
printf("任务名:%s\r\n",status_array2->pcTaskName);
printf("任务优先级:%ld\r\n",status_array2->uxCurrentPriority);
printf("任务编号:%ld\r\n",status_array2->xTaskNumber);
printf("任务状态:%d\r\n",status_array2->eCurrentState);
/*根据任务名获取该任务的任务句柄*/
task_handle = xTaskGetHandle( "task1" );
printf("任务句柄:%#x\r\n",(int)task_handle);
printf("task1的任务句柄:%#x\r\n",(int)task1_handler);
/*获取任务状态*/
state = eTaskGetState( task2_handler );
printf("当前task2的任务状态为:%d\r\n",state);
/*相对于“获取所有任务状态信息”这个好用*/
/*以“表格”形式获取所有任务的信息 */
vTaskList( task_buff );
printf("%s\r\n",task_buff);
while(1)
{
/*获取任务的任务栈历史剩余最小值*/ //task_stack_min=uxTaskGetStackHighWaterMark( task2_handler );
//printf("task2历史剩余最小堆栈为%ld\r\n",task_stack_min);
vTaskDelay(1000);
}
}
队列
动态方式创建:
#define xQueueCreate ( uxQueueLength, uxItemSize )
xQueueGenericCreate( ( uxQueueLength ), ( uxItemSize ),(queueQUEUE_TYPE_BASE))
参数:
uxQueueLength 队列长度
uxItemSize 队列项目的大小
返回值:
NULL 队列创建失败
其他值 队列创建成功,返回队列句柄
#define queueSEND_TO_BACK ( ( BaseType_t ) 0 )/* 写入队列尾部 */
#define queueSEND_TO_FRONT ( ( BaseType_t ) 1 )/* 写入队列头部 */
#define queueOVERWRITE ( ( BaseType_t ) 2 )/* 覆写队列*/
注意:覆写方式写入队列,只有在队列的队列长度为 1 时,才能够使用
往队列写入消息API函数
函数 | 描述 |
xQueueSend() | 往队列的尾部写入消息 |
xQueueSendToBack() | 同 xQueueSend() |
xQueueSendToFront() | 往队列的头部写入消息 |
xQueueOverwrite() | 覆写队列消息(只用于队列长度为 1 的情况) |
xQueueSendFromISR() | 在中断中往队列的尾部写入消息 |
xQueueSendToBackFromISR() | 同 xQueueSendFromISR() |
xQueueSendToFrontFromISR() | 在中断中往队列的头部写入消息 |
xQueueOverwriteFromISR() | 在中断中覆写队列消息(只用于队列长度为 1 的情况) |
队列写入消息
#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 )
#define queueSEND_TO_BACK ( ( BaseType_t ) 0 )/* 写入队列尾部 */
#define queueSEND_TO_FRONT ( ( BaseType_t ) 1 )/* 写入队列头部 */
#define queueOVERWRITE ( ( BaseType_t ) 2 )/* 覆写队列*/
注意:覆写方式写入队列,只有在队列的队列长度为 1 时,才能够使用
往队列写入消息函数入口参数解析:
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函数:
函数 | 描述 |
xQueueReceive() | 从队列头部读取消息,并删除消息 |
xQueuePeek() | 从队列头部读取消息 |
xQueueReceiveFromISR() | 在中断中从队列头部读取消息,并删除消息 |
xQueuePeekFromISR() | 在中断中从队列头部读取消息 |
此函数用于在任务中,从队列中读取消息,并且消息读取成功后,会将消息从队列中移除。
BaseType_t xQueueReceive( QueueHandle_t xQueue,
void * const pvBuffer,
TickType_t xTicksToWait )
参数:
ueue 待读取的队列
pvBuffer 信息读取缓冲区
xTicksToWait 阻塞超时时间
此函数用于在任务中,从队列中读取消息, 但与函数 xQueueReceive()不同,此函数在成功读取消息后,并不会移除已读取的消息!
BaseType_t xQueuePeek( QueueHandle_t xQueue,
void * const pvBuffer,
TickType_t xTicksToWait )
参数:
ueue 待读取的队列
pvBuffer 信息读取缓冲区
xTicksToWait 阻塞超时时间
返回值:
pdTRUE 读取成功
pdFALSE 读取失败
使用示例:
QueueHandle_t key_queue; /*小数据句柄*/
QueueHandle_t big_data_queue; /*大数据句柄*/
char buff[100] = {"11111111111111111111111***************************1111111111111111111111111\r\n"};
void FreeRTOS_Dome(void)
{
key_queue = xQueueCreate( 2, sizeof(uint8_t));
if(key_queue != NULL)
printf("队列key_queue创建成功\r\n");
else
printf("队列key_queue创建失败\r\n");
big_data_queue = xQueueCreate(2, sizeof(char *));
if(big_data_queue != NULL)
printf("队列big_data_queue创建成功\r\n");
else
printf("队列big_data_queue创建失败\r\n");
xTaskCreate(Start_Task,"Start_Task",START_STK_SZIE,NULL,START_TASK_PRIO,&START_Handle_t);
vTaskStartScheduler();}
void Task2(void *p)
{
BaseType_t err;
uint8_t key_val=0;
char *buf;
buf = &buff[0];
while(1)
{
if(KeyScanf(GPIOC,GPIO_PIN_13) == 1)
{
err = xQueueSend(big_data_queue,&buf,0);
if(err == pdTRUE)
printf("队列big_data_queue发送成功\r\n");
else
printf("队列big_data_queue发送失败\r\n");
}
// if(KeyScanf(GPIOA,GPIO_PIN_0) == 1)
// {
// err = xQueueReceive(key_queue,&key_val,0);
// if(err == pdTRUE)
// printf("队列key_queue读取成功,data:%d\r\n",key_val);
// else
// printf("队列key_queue读取失败\r\n");
// }
vTaskDelay(10);
}
}
void Task3(void *p)
{
uint8_t key_val;
BaseType_t err;
char *buf;
while(1)
{
key_val = 1;
if(KeyScanf(GPIOA,GPIO_PIN_0) == 1)
{
// err = xQueueSend(key_queue,&key_val,0);
// if(err == pdTRUE)
// printf("队列key_queue发送成功\r\n");
// else
// printf("队列key_queue发送失败\r\n");
// }
// if(KeyScanf(GPIOC,GPIO_PIN_13) == 1)
// {
err = xQueueReceive(big_data_queue,&buf,0);
if(err == pdTRUE)
printf("队列big_data_queue读取成功,data:%s\r\n",buf);
else
printf("队列big_data_queue读取失败\r\n");
}
vTaskDelay(10);
}
}
二值信号量
动态创建二值信号量函数:
·SemaphoreHandle_t xSemaphoreCreateBinary( void )
参数:无
返回值:创建失败 NULL
创建成功 二值信号量的句柄
静态创建二值信号量函数:
·xSemaphoreCreateBinaryStatic()
释放二值信号量函数
任务中:
·BaseType_t xSemaphoreGive( xSemaphore )
参数:要释放的信号量句柄
返回值: pdPASS 释放信号量成功
errQUEUE_FULL 释放信号量失败
中断中:
·BaseType_t xSemaphoreGiveFromISR(
SemaphoreHandle_t xSemaphore,
BaseType_t* pxHigherPriorityTask Woken)
参数: xSemaphore: 要释放的信号量句柄。
pxHigherPriorityTaskWoken:标记退出此函数以后是否进行任 务切换,这个变量的值由这三个函 数来设置的,用户不用进行设置, 用户只需要提供一个变量来保存 这个值就行了。当此值为pdTRUE 的时候在退出中断服务函数之前 一定要进行一次任务切换。
返回值: pdPASS 释放信号量成功。
errQUEUE_FULL 释放信号量失败。
获取二值信号量函数:
任务中:
·BaseType_t xSemaphoreTake( xSemaphore, xBlockTime )
参数: xSemaphore 要获取的信号量句柄
xBlockTime 阻塞时间
返回值: pdTRUE 获取信号量成功
pdFALSE 超时,获取信号量失败
中断中:
·BaseType_t xSemaphoreTakeFromISR(
SemaphoreHandle_t xSemaphore,
BaseType_t * pxHigherPriority Task Woken)
参数:
xSemaphore:要获取的信号量句柄。
pxHigherPriorityTaskWoken: 标记退出此函数以后是否进行任务切换,这个变量的值由这三个函数来设置的,用户不用进行设置,用户只需要提供一个变量来保存这个值就行了。当此值为pdTRUE的时候在退出中断服务函数之前一定要进行一次任务切换。
返回值: pdPASS: 获取信号量成功。
pdFALSE: 获取信号量失败。
使用示例:
QueueHandle_t semphorc_Handle;
semphorc_Handle = xSemaphoreCreateBinary();
if(semphorc_Handle != NULL)
printf("semphorc_Handle succeeded\r\n");
void Task1(void *p)
{
BaseType_t xReturn;
while(1)
{
if(KeyScanf(GPIOC,GPIO_PIN_13) == 1)
{
if(semphorc_Handle != NULL)
{
xReturn = xSemaphoreGive(semphorc_Handle);
if(xReturn == pdPASS)
printf("xSemaphoreGive succeeded\r\n");
else
printf("xSemaphoreGive failed\r\n");
}
}
}
}
void Task2(void *p)
{
uint8_t i=0;
BaseType_t xReturn;
while(1)
{
xReturn = xSemaphoreTake(semphorc_Handle,1000);
if(xReturn == pdTRUE)
printf("xSemaphoreTake succeeded \r\n");
else
printf("xSemaphoreTake failed num%d\r\n",++i);
}
}
计数型二值信号量
创建计数型二值信号量函数:
动态方式:
·SemaphoreHandle_t xSemaphoreCreateCounting(
UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount )
参数:
uxMaxCount: 计数信号量最大计数值,当信号量值等于此值的 时候释放信号量就会失败。
uxInitialCount:计数信号量初始值。
返回值:
NULL: 计数型信号量创建失败。
其他值: 计数型信号量创建成功,返回计数型信号量句柄。
静态方式:
·SemaphoreHandle_t xSemaphoreCreateCountingStatic(
UBaseType_t uxMaxCount,
UBaseType_t uxInitialCount,
StaticSemaphore_t *pxSemaphoreBuffer )
参数:
uxMaxCount: 计数信号量最大计数值,当信号量值等于此 值的时候释放信号量就会失败。
uxInitialCount: 计数信号量初始值。
pxSemaphoreBuffer: 指向一个StaticSemaphore_t类型的变量, 用来保存信号量结构体。
返回值:
NULL: 计数型信号量创建失败。
其他值: 计数型号量创建成功,返回计数型信号量句柄。
uxSemaphoreGetCount() 返回信号量的计数值
计数型信号量的释放和获取与二值信号量相同 !
使用示例:
QueueHandle_t cnt_semphorc_Handle;
#define cnt_semphorc_MAX 100
#define cnt_semphorc_Init 100 /* or 0 */
cnt_semphorc_Handle = xSemaphoreCreateCounting(cnt_semphorc_MAX,cnt_semphorc_Init);
if(cnt_semphorc_Handle != NULL)
printf("计数型信号量创建成功\r\n");
void Task1(void *p)
{
BaseType_t xReturn;
while(1)
{
if(KeyScanf(GPIOC,GPIO_PIN_13) == 1)
{
if(cnt_semphorc_Handle != NULL)
xReturn = xSemaphoreGive(cnt_semphorc_Handle); /*释放信号量*/
}
vTaskDelay(10);
}
}
void Task2(void *p)
{
BaseType_t xReturn;
while(1)
{
xReturn = xSemaphoreTake(cnt_semphorc_Handle,portMAX_DELAY);
if(xReturn == pdTRUE)
printf("信号量计数值为:%d\r\n",(int)uxSemaphoreGetCount(cnt_semphorc_Handle));
vTaskDelay(1000);
}
}
互斥信号量
创建互斥信号量函数
动态创建互斥信号量函数
·SemaphoreHandle_t xSemaphoreCreateMutex( void )
参数:
无。
返回值:
NULL: 互斥信号量创建失败。
其他值: 创建成功的互斥信号量的句柄。
静态创建互斥信号量函数
·SemaphoreHandle_t xSemaphoreCreateMutexStatic
( StaticSemaphore_t *pxMutexBuffer )
参数:
pxMutexBuffer: 此参数指向一个 StaticSemaphore_t类型 的变量,用来保存信号量结构体。
返回值:
NULL: 互斥信号量创建失败。
其他值: 创建成功的互斥信号量的句柄。
注意:创建互斥信号量时,会主动释放一次信号量
·互斥信号量的释放和获取函数与二值信号量相同 !只不过互斥信号量不 支持中断中调用
使用示例:
QueueHandle_t mutex_semphorc_Handle;
mutex_semphorc_Handle = xSemaphoreCreateMutex(); /*创建互斥信号量,并且主动释放一次信号量*/
if(mutex_semphorc_Handle != NULL)
printf("semphorc_Handle succeeded\r\n");
void Task1(void *p)
{
while(1)
{
printf("低优先级任务获取信号量\r\n");
xSemaphoreTake(mutex_semphorc_Handle,portMAX_DELAY);
printf("低优先级任务正在运行\r\n");
delay_ms(3000);
printf("低优先级任务释放信号量\r\n");
xSemaphoreGive(mutex_semphorc_Handle);
vTaskDelay(1000);
}
}
void Task2(void *p)
{
while(1)
{
printf("中优先级任务正在运行\r\n");
vTaskDelay(1000);
}
}
void Task3(void *p)
{
while(1)
{
printf("高优先级任务获取信号量\r\n");
xSemaphoreTake(mutex_semphorc_Handle,portMAX_DELAY);
printf("高优先级任务正在运行\r\n");
delay_ms(1000);
printf("高优先级任务释放信号量\r\n");
xSemaphoreGive(mutex_semphorc_Handle);
vTaskDelay(1000);
}
}
任务通知
发送通知相关API函数:
函数 | 描述 |
xTaskNotify() | 发送通知,带有通知值 |
xTaskNotifyAndQuery() | 发送通知,带有通知值并且保留接收任务的原通知值 |
xTaskNotifyGive() | 发送通知,不带通知值 |
xTaskNotifyFromISR() | 在中断中发送任务通知 |
xTaskNotifyAndQueryFromISR() | |
vTaskNotifyGiveFromISR() |
BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify,
UBaseType_t uxIndexToNotify,
uint32_t ulValue,
eNotifyAction eAction,
uint32_t * pulPreviousNotificationValue )
形参 | 描述 |
xTaskToNotify | 接收任务通知的任务句柄 |
uxIndexToNotify | 任务的指定通知(任务通知相关数组成员) |
ulValue | 任务通知值 |
eAction | 通知方式(通知值更新方式) |
pulPreviousNotificationValue | 用于保存更新前的任务通知值(为NULL则不保存) |
任务通知方式共有以下几种:
typedef enum
{
eNoAction = 0, /* 无操作 */
eSetBits /* 更新指定bit */
eIncrement /* 通知值加一 */
eSetValueWithOverwrite /* 覆写的方式更新通知值 */
eSetValueWithoutOverwrite /* 不覆写通知值 */
} eNotifyAction;
接收通知相关API函数:
函数 | 描述 |
ulTaskNotifyTake() | 获取任务通知,可以设置在退出此函数的时候将任务通知值清零或者减一。 当任务通知用作二值信号量或者计数信号量的时候,使用此函数来获取信号量。 |
xTaskNotifyWait() | 获取任务通知,比 ulTaskNotifyTak()更为复杂,可获取通知值和清除通知值的指定位 |
·当任务通知用作于信号量时,使用函数获取信号量:ulTaskNotifyTake()
·当任务通知用作于事件标志组或队列时,使用此函数来获取: xTaskNotifyWait()
·#define ulTaskNotifyTake( xClearCountOnExit , xTicksToWait ) \
ulTaskGenericNotifyTake( ( tskDEFAULT_INDEX_TO_NOTIFY ), \
( xClearCountOnExit ), \
( xTicksToWait ) )此函数用于接收任务通知值,可以设置在退出此函数的时候将任务通知值清零或者减一
形参 | 描述 |
uxIndexToWaitOn | 任务的指定通知(任务通知相关数组成员) |
xClearCountOnExit | 指定在成功接收通知后,将通知值清零或减 1, pdTRUE:把通知值清零;pdFALSE:把通知值减一 |
xTicksToWait | 阻塞等待任务通知值的最大时 |
BaseType_t xTaskGenericNotifyWait( UBaseType_t uxIndexToWaitOn,
uint32_t ulBitsToClearOnEntry,
uint32_t ulBitsToClearOnExit,
uint32_t * pulNotificationValue,
TickType_t xTicksToWait );此函数用于获取通知值和清除通知值的指定位值,适用于模拟队列和事件标志组,使用该函数来获取任务通知 。
形参 | 描述 |
uxIndexToWaitOn | 任务的指定通知(任务通知相关数组成员) |
ulBitesToClearOnEntry | 等待前清零指定任务通知值的比特位(旧值对应bit清0) |
ulBitesToClearOnExit | 成功等待后清零指定的任务通知值比特位(新值对应bit清0) |
pulNotificationValue | 用来取出通知值(如果不需要取出,可设为NULL) |
xTicksToWait | 阻塞等待任务通知值的最大时间 |
返回值 | 描述 |
pdTRUE | 等待任务通知成功 |
pdFALSE | 等待任务通知失败 |
·使用示例(任务通知模拟二值信号量实验):
/*任务一,发送任务通知值*/
void Task1(void *p)
{
uint8_t key_val = 0;
while(1)
{
key_val = KeyScanf();
if(key_val == KEY0_PRES)
{
// printf("任务通知模拟二值信号量释放\r\n");
// xTaskNotifyGive(Task2_Handle_t);
printf("任务通知模拟计数型信号量,计数值加1\r\n");
xTaskNotifyGive(Task2_Handle_t);
}
vTaskDelay(10);
}
}
/*任务二,接收任务通知值*/
void Task2(void *p)
{
uint32_t ulReturn;
while(1)
{
// ulReturn = ulTaskNotifyTake(pdTRUE,portMAX_DELAY);
// if(ulReturn == pdTRUE)
// printf("任务通知模拟二值信号量接收成功\r\n");
ulReturn = ulTaskNotifyTake(pdFALSE,portMAX_DELAY);
if(ulReturn != 0)
printf("任务通知模拟计数型号量,计数值减一 :%d\r\n",ulReturn);
vTaskDelay(1000);
}
}
·使用示例(任务通知模拟消息邮箱):
/*任务一,发送任务通知值*/
void Task1(void *p)
{
uint8_t key_val = 0;
while(1)
{
key_val = KeyScanf();
if((key_val !=0) && Task2_Handle_t != NULL)
{
printf("发送任务通知模拟消息邮箱发送,发送的键值:%d\r\n",key_val);
xTaskNotify(Task2_Handle_t,key_val,eSetValueWithoutOverwrite);
}
vTaskDelay(10);
}
}
/*任务二,接收任务通知值*/
void Task2(void *p)
{
uint32_t noyify_val = 0;
while(1)
{
xTaskNotifyWait(0,0xffffffff,&noyify_val,portMAX_DELAY);
switch(noyify_val)
{
case KEY0_PRES:
printf("KEY0按下,接收到的通知值为:%d\r\n",noyify_val);
break;
case KEY1_PRES:
printf("KEY1按下,接收到的通知值为:%d\r\n",noyify_val);
break;
default: break;
}
}
}
·使用示例(任务通知模拟事件标志组):
#define EventBIT_0 (1 << 0)
#define EventBIT_1 (1 << 1)
void Task1(void *p)
{
uint8_t key_val=0;
while(1)
{
key_val = KeyScanf();
if(key_val == KEY0_PRES)
{
printf("将bit0位置1 \r\n");
xTaskNotify(Task2_Handle_t,EventBIT_0,eSetBits);
}
else if(key_val == KEY1_PRES)
{
printf("将bit1位置1 \r\n");
xTaskNotify(Task2_Handle_t,EventBIT_1,eSetBits);
}
vTaskDelay(10);
}
}
void Task2(void *p)
{
uint32_t notiyf_val = 0,event_bit = 0;
while(1)
{
xTaskNotifyWait(0,0xffffffff,¬iyf_val,portMAX_DELAY);
if(notiyf_val & EventBIT_0)
{
event_bit |= EventBIT_0;
}
if(notiyf_val & EventBIT_1)
{
event_bit |= EventBIT_1;
}
if(event_bit == (EventBIT_0 | EventBIT_1))
{
event_bit = 0;
printf("任务通知模拟事件标志组接收成功\r\n");
}
vTaskDelay(10);
}
}