目录
api
vTaskStartScheduler() 开启任务调度器
taskENTER_CRITICAL(); 进入临界区
taskEXIT_CRITICAL(); 退出临界区
vTaskDelete(AppTaskCreate_Handle); 删除任务 参数:任务句柄
xTaskCreateStatic() sram静态创建任务 详见后面
xTaskCreate() 动态创建任务
vTaskDelete() 删除任务 如果是删除自身, 则形参为 NULL
vTaskDelay() 延时函数 INCLUDE_vTaskDelay置1
vTaskDelayUntil() 绝对延时
vTaskSuspend() 任务挂起 参数:任务句柄
vTaskResume() 任务恢复 参数:任务句柄
xTaskResumeFromISR() 任务恢复 中断中使用 需INCLUDE_vTaskSuspend 和 INCLUDE_vTaskResumeFromISR置1
vTaskSuspendAll() 挂起所有任务
xTaskResumeAll() 恢复所有挂起任务 vTaskSuspendAll() 多少次,他就要多少次
taskYIELD() 任务切换
SRAM静态创建: xTaskCreateStatic
任务必须死循环,阻塞
1 . configSUPPORT_STATIC_ALLOCATION开启
2 .实现vApplicationGetIdleTaskMemory()与 vApplicationGetTimerTaskMemory() 设定的空闲(Idle)任务与定时器(Timer)任务的堆栈大小
static StackType_t Idle_Task_Stack[configMINIMAL_STACK_SIZE]; static StackType_t Timer_Task_Stack[configTIMER_TASK_STACK_DEPTH]; static StaticTask_t Idle_Task_TCB; static StaticTask_t Timer_Task_TCB; void vApplicationGetTimerTaskMemory(StaticTask_t **ppxTimerTaskTCBBuffer, StackType_t **ppxTimerTaskStackBuffer, uint32_t *pulTimerTaskStackSize) { *ppxTimerTaskTCBBuffer=&Timer_Task_TCB; *ppxTimerTaskStackBuffer=Timer_Task_Stack; *pulTimerTaskStackSize=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; }
3.创建任务
static StackType_t AppTaskCreate_Stack[128]; static StaticTask_t AppTaskCreate_TCB; AppTaskCreate_Handle = xTaskCreateStatic((TaskFunction_t )AppTaskCreate,//任务函数 (const char* )"AppTaskCreate",//任务名称 (uint32_t )128, //堆栈大小 (void* )NULL,//参数 (UBaseType_t )3, //优先级 (StackType_t* )AppTaskCreate_Stack,//任务堆栈 (StaticTask_t* )&AppTaskCreate_TCB);//任务控制块
4.开启任务调度器
vTaskStartScheduler()
动态创建任务
xReturn = xTaskCreate((TaskFunction_t )AppTaskCreate, /* 任务入口函数 */ (const char* )"AppTaskCreate",/* 任务名字 */ (uint16_t )512, /* 任务栈大小 */ (void* )NULL,/* 任务入口函数参数 */ (UBaseType_t )1, /* 任务的优先级 */ (TaskHandle_t* )&AppTaskCreate_Handle);/* 任务控制块指针 */ /* 启动任务调度 */ if (pdPASS == xReturn) vTaskStartScheduler(); /* 启动任务,开启调度 */ else return -1;
消息队列
1.创建消息队列 xQueueCreate() xQueueCreateStatic()
#define QUEUE_LEN 4 /* 队列的长度,最大可包含多少个消息 */ #define QUEUE_SIZE 4 /* 队列中每个消息大小(字节) */ QueueHandle_t Test_Queue; Test_Queue = xQueueCreate((UBaseType_t ) QUEUE_LEN,/* 消息队列的长度 */ (UBaseType_t ) QUEUE_SIZE);/* 消息的大小 */ if (NULL != Test_Queue) printf("创建 Test_Queue 消息队列成功!\r\n");
#define QUEUE_LENGTH 10 #define ITEM_SIZE sizeof( uint64_t ) /* 该变量用于存储队列的数据结构 */ static StaticQueue_t xStaticQueue /* 该数组作为队列的存储区域,大小至少有 uxQueueLength * uxItemSize 个字节 */ uint8_t ucQueueStorageArea[ QUEUE_LENGTH * ITEM_SIZE ]; xQueue = xQueueCreateStatic( QUEUE_LENGTH, /* 队列深度 */ ITEM_SIZE, /* 队列数据单元的单位 */ ucQueueStorageArea,/* 队列的存储区域 */ &xStaticQueue ); /* 队列的数据结构 */
删除消息队列vQueueDelete()
发送消息xQueueSend()
xReturn = xQueueSend( Test_Queue, /* 消息队列的句柄 */ &send_data1,/* 发送的消息内容 */ 0 ); /* 等待时间 0 */ if (pdPASS == xReturn) printf("消息 send_data1 发送成功!\n\n");
接受消息xQueueReceive() xQueuePeek()
xReturn = xQueueReceive( Test_Queue, /* 消息队列的句柄 */ &r_queue, /* 发送的消息内容 */ portMAX_DELAY); /* 等待时间 一直等 */ if (pdTRUE== xReturn) printf("本次接收到的数据是:%d\n\n",r_queue); else printf("数据接收出错,错误代码: 0x%lx\n",xReturn);
xQueuePeek() 不会删除消息队列中的消息使用同上
信号量(Semaphore)
信号量释放函数xSemaphoreGive()
信号量获取函数xSemaphoreTake()
信号量删除函数 vSemaphoreDelete()
二值信号量xSemaphoreCreateBinary()
互斥量有优先级继承机制,二值信号量则没有这个机制,这使得二值信号量更偏 向应用于同步功能,用作同步时,信号量在创建后应被置为空
SemaphoreHandle_t BinarySem_Handle =NULL; BinarySem_Handle = xSemaphoreCreateBinary(); if (NULL != BinarySem_Handle) printf("BinarySem_Handle 二值信号量创建成功!\r\n"); BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */ xReturn = xSemaphoreTake(BinarySem_Handle,/* 二值信号量句柄 */ portMAX_DELAY); /* 等待时间 */ if (pdTRUE == xReturn) printf("BinarySem_Handle 二值信号量获取成功!\n\n"); xReturn = xSemaphoreGive( BinarySem_Handle );//给出二值信号量 if ( xReturn == pdTRUE ) printf("BinarySem_Handle 二值信号量释放成功!\r\n"); else printf("BinarySem_Handle 二值信号量释放失败!\r\n");
计数信号量xSemaphoreCreateBinary()
SemaphoreHandle_t CountSem_Handle =NULL; CountSem_Handle = xSemaphoreCreateCounting(5,5);//计数信号量的最大值,创建计数信号量的初始值 if (NULL != CountSem_Handle) printf("CountSem_Handle 计数信号量创建成功!\r\n");
互斥信号量xSemaphoreCreateMutex()
是特殊的二值信号量,更适用 于简单互锁,也就是保护临界资源
MuxSem_Handle= xSemaphoreCreateMutex(); if (MuxSem_Handle!= NULL ) { /* 互斥量创建成功 */ }
递归信号量xSemaphoreCreateRecursiveMutex()
configSUPPORT_DYNAMIC_ALLOCATION 和 configUSE_RECURSIVE_MUTEXES 均定义 为 1
对于已经获取递归互斥量的任务可以重复获取该递归互斥量,该任务拥有递归信号量的所有权,任务成功获取几次递 归互斥量,就要返还几次,在此之前递归互斥量都处于无效状态,其他任务无法获取,只 有持有递归信号量的任务才能获取与释放。
xMutex = xSemaphoreCreateRecursiveMutex(); if ( xMutex != NULL ) { /* 递归互斥量创建成功 */ }
递归互斥量获取函数 xSemaphoreTakeRecursive()
递归互斥量释放函数 xSemaphoreGiveRecursive()
事件
事件是一种实现任务间通信的机制,主要用于实现多任务间的同步,但事件通信只能 是事件类型的通信,无数据传输。与信号量不同的是,它可以实现一对多,多对多的同步。 即一个任务可以等待多个事件的发生:可以是任意一个事件发生时唤醒任务进行事件处理; 也可以是几个事件都发生后才唤醒任务进行事件处理
事件只与任务相关联,事件相互独立,一个 32 位的事件集合(EventBits_t 类型的 变量,实际可用与表示事件的只有 24位),用于标识该任务发生的事件类型,其 中每一位表示一种事件类型(0 表示该事件类型未发生、1 表示该事件类型已经发 生),一共 24 种事件类型。
事件仅用于同步,不提供数据传输功能。
事件无排队性,即多次向任务设置同一事件(如果任务还未来得及读走),等效于 只设置一次。
允许多个任务对同一事件进行读写操作。
支持事件等待超时机制
事件创建函数 xEventGroupCreate()
事件删除函数 vEventGroupDelete()
static EventGroupHandle_t Event_Handle =NULL; /* 创建 Event_Handle */ Event_Handle = xEventGroupCreate(); if (NULL != Event_Handle) { printf("Event_Handle 事件创建成功!\r\n"); /* 创建成功,可以删除 */ xEventGroupCreate(Event_Handle); } else /* 创建失败,应为内存空间不足 */
事件组置位函数xEventGroupSetBits()
#define KEY1_EVENT (0x01 << 0)//设置事件掩码的位 0 xEventGroupSetBits(Event_Handle,KEY1_EVENT);
等待事件函数 xEventGroupWaitBits()
EventBits_t r_event; r_event = xEventGroupWaitBits(Event_Handle, /* 事件对象句柄 */ KEY1_EVENT|KEY2_EVENT,/* 接收任务感兴趣的事件 */ pdTRUE, /* 退出时清除事件位 */ pdTRUE, /* 满足感兴趣的所有事件 */ portMAX_DELAY);/* 指定超时事件,一直等 *
软件定时器
软件定时器创建函数 xTimerCreate()
configUSE_TIMERS 和 configSUPPORT_DYNAMIC_ALLOCATION 均 定义为 1
软件定时器在创建成功后是处于休眠状态的,可以使用 xTimerStart()、xTimerReset()、 xTimerStartFromISR() 、 xTimerResetFromISR() 、 xTimerChangePeriod() 和 xTimerChangePeriodFromISR()这些函数将其状态转换为活跃态
static TimerHandle_t Swtmr1_Handle =NULL; /* 软件定时器句柄 */ static TimerHandle_t Swtmr2_Handle =NULL; /* 软件定时器句柄 */ /* 周期模式的软件定时器 1,定时器周期 1000(tick)*/ Swtmr1_Handle=xTimerCreate((const char*)"AutoReloadTimer", (TickType_t)1000,/* 定时器周期 1000(tick) */ (UBaseType_t)pdTRUE,/* 周期模式 */ (void* )1,/* 为每个计时器分配一个索引的唯一 ID */ (TimerCallbackFunction_t)Swtmr1_Callback); /* 回调函数 */ if (Swtmr1_Handle != NULL){ xTimerStart(Swtmr1_Handle,0); //开启周期定时器 } xTimerStop(Swtmr1_Handle,0); //停止软件定时器 xTimerDelete(Swtmr1_Handle,0); //删除软件定时器
xTimerStart()
xTimerStop()
xTimerDelete()
任务通知
任务通知可以替代二值信号量、计数信号量、事件组,也可以替代 长度为 1 的队列
二值信号
static TaskHandle_t xTask1 = NULL xTaskCreate(prvTask1, "Task1", 200, NULL, tskIDLE_PRIORITY, &xTask1); /* 向 prvTask2()发送一个任务通知,让其退出阻塞状态 */ xTaskNotifyGive( xTask2 ); /* 阻塞在 prvTask2()的任务通知上 如果没有收到通知,则一直等待*/ ulTaskNotifyTake( pdTRUE, portMAX_DELAY )
消息
发送
BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为 pdPASS */ #if USE_CHAR char test_str1[] = "this is a mail test 1";/* 消息 test1 */ char test_str2[] = "this is a mail test 2";/* 消息 test2 */ #else uint32_t send1 = 1; uint32_t send2 = 2; #endif xReturn = xTaskNotify( Receive1_Task_Handle, /*任务句柄*/ #if USE_CHAR (uint32_t)&test_str1, /*发送的数据,最大为 4 字节 */ #else send1, /* 发送的数据,最大为 4 字节 */ #endif eSetValueWithOverwrite );/*覆盖当前通知*/ if ( xReturn == pdPASS ) printf("Receive1_Task_Handle 任务通知释放成功!\r\n"); }
接收
xReturn=xTaskNotifyWait(0x0, //进入函数的时候不清除任务 bit ULONG_MAX, //退出函数的时候清除所有的 bit #if USE_CHAR (uint32_t *)&r_char,//保存任务通知值 #else &r_num, //保存任务通知值 #endif portMAX_DELAY); //阻塞时间 if ( pdTRUE == xReturn ) #if USE_CHAR printf("Receive1_Task 任务通知为 %s \n",r_char); #else printf("Receive1_Task 任务通知为 %d \n",r_num); #endif
任务通知代替计数信号量
获取任务通知 ,没获取到则不等待 take_num=ulTaskNotifyTake(pdFALSE,0);// if (take_num > 0) printf( "KEY1 被按下,成功申请到停车位。当前车位为 %d \n", take_num - 1); else printf( "KEY1 被按下,车位已经没有了。按 KEY2 释放车位\n" ); /* 释放一个任务通知 */ xTaskNotifyGive(Take_Task_Handle);//发送任务通
任务通知代替事件组
#define KEY1_EVENT (0x01 << 0)//设置事件掩码的位 0 #define KEY2_EVENT (0x01 << 1)//设置事件掩码的位 1 xReturn = xTaskNotifyWait(0x0, //进入函数的时候不清除任务 bit ULONG_MAX, //退出函数的时候清除所有的 bitR &r_event, //保存任务通知值 portMAX_DELAY); //阻塞时间 if ( pdTRUE == xReturn ) { last_event |= r_event; /* 如果接收完成并且正确 */ if (last_event == (KEY1_EVENT|KEY2_EVENT)) { last_event = 0; /* 上一次的事件清零 */ printf ( "Key1 与 Key2 都按下\n"); LED1_TOGGLE; //LED1 反转 } else /* 否则就更新事件 */ last_event = r_event; /* 更新上一次触发的事件 */ } } xTaskNotify((TaskHandle_t)LED_Task_Handle,//接收任务通知的任务句柄 (uint32_t)KEY1_EVENT, //要触发的事件 (eNotifyAction)eSetBits); //设置任务通知值中的位 }
内存管理
1 void *pvPortMalloc( size_t xSize ); //内存申请函数
2 void vPortFree( void *pv ); //内存释放函数
3 void vPortInitialiseBlocks( void ); //初始化内存堆函数
4 size_t xPortGetFreeHeapSize( void ); //获取当前未分配的内存堆大小
5 size_t xPortGetMinimumEverFreeHeapSize( void ); //获取未分配的内存堆历史最小值
uint8_t *Test_Ptr = NULL; Test_Ptr = pvPortMalloc(1024); uint32_t g_memsize; /* 获取当前内剩余存大小 */ g_memsize = xPortGetFreeHeapSize(); vPortFree(Test_Ptr); //释放内存
中断管理
最低优先级 #define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
管理的最高优先级 #define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 5
可以管理5-15优先级的中断
portDISABLE_INTERRUPTS() 关中断
portENBABLE_INTERRUPTS() 开中断