
偏差点全局变量也能实现任务与任务中断与任务之间的数据交流OS中全局变量弊端数据无保护导致数据不安全多个任务同时对改变量操作时数据易受损队列解决全局变量痛点任务读写队列都会进入临界区关中断防止其他任务打断是个原子操作队列定义任务与任务中断与任务之间数据交流的机制特点入队出队方式最先入队的数据会最先被读取数据传递方式入队支持拷贝数据和拷贝数据地址多任务访问任务与中断都可读写队列出队入队阻塞//入队阻塞 情况队列满了此时写不进去数据 将该任务的状态列表项挂载在pxDelayedTaskList 将该任务的事件列表项挂载在xTaskWaitingToSend //出队阻塞 情况队列空了此时读取不了数据 将该任务的状态列表项挂载在pxDelayedTaskList 将该任务的事件列表项挂载在xTaskWaitingToReceive队列创建函数函数xQueueCreate入参队列长度与队列项目大小返回值 NULL:队列创建失败 队列句柄队列写函数函数xQueueSend 入参队列句柄待写入数据/地址阻塞时间 返回值BaseType_t 描述往队列尾部写入数据 [注意]最大阻塞时间portMAX_DELAY函数xQueueSendToFront 描述往队列头部写入数据函数xQueueOverwrite 描述覆写队列消息(只用与队列长度为1的情况)//队列写函数调用示例 uint8_t keynum 0 char buf[100] {0}; xQueueSend(queue, keynum, portMAX_DELAY); //拷贝数据 xQueueReceive(queue, buf, portMAX_DELAY); //拷贝地址队列读函数函数xQueueReceive 入参队列句柄缓冲区阻塞时间 返回值BaseType_t 描述从队列头部读取数据并删除数据函数xQueuePeek 描述从队列头部读取数据并不会删除数据//队列读函数调用示例 uint8_t keynum 0 char *buf 0; xQueueReceive(queue, keynum, portMAX_DELAY); //读取数据 xQueueReceive(queue, buf, portMAX_DELAY); //读取内存 //操作数据(打印) printf(%d, keynum); printf(%s, buf);信号量作用解决同步问题的机制实现对共享资源的有序访问场景二值信号量本质是一个同步工具。它的典型用法是“一个中断/任务给出Give另一个任务等待Take”用于传递一个“事件已发生”的信号 互斥信号量本质是一个资源保护工具。它的典型用法是“同一个任务获取Take再释放Give”用于保护一个共享资源如一个硬件外设或全局变量不被多个任务同时访问。信号量初值二值信号量0 计数信号量自设 互斥信号量1二值信号量二值信号量创建函数xSemaphoreCreateBinary 入参无 返回值失败NULL成功信号量句柄二值信号量释放函数xSemaphoreGive 入参信号量句柄 返回值成功pdPASS二值信号量获取函数xSemaphoreTake 入参信号量句柄阻塞时间 返回值成功pdTRUE二值信号量导致的优先级翻转问题 优先级翻转定义高优先级的任务反而满执行低优先级的任务反而优先执行计数信号量适用场景 事件计数初值设为0 资源管理初值设为最大资源数计数信号量创建函数xSemaphoreCreateCounting 入参最大计数值初始计数值 返回值失败NULL成功信号量句柄计数信号量释放函数xSemaphoreGive 入参信号量句柄 返回值成功pdPASS计数信号量获取函数xSemaphoreTake 入参信号量句柄阻塞时间 返回值成功pdTRUE计数信号量计数值获取函数uxSemaphoreGetCount 入参信号量句柄 返回值UBaseType_t互斥信号量定义拥有优先级继承的二值信号量优先级继承 当互斥型信号量正在被一个低优先级任务持有时如果此时有个高优先级的任务也尝试获取这个互斥量那么这个高优先级任务就会被阻塞不过高优先级任务会将低优先级任务提升到与自己相同的优先级互斥信号量创建函数xSemaphoreCreateMutex 入参无 返回值失败NULL成功信号量句柄互斥信号量释放函数xSemaphoreGive 入参信号量句柄 返回值成功pdPASS互斥信号量获取函数xSemaphoreTake 入参信号量句柄阻塞时间 返回值成功pdTRUE队列集需求队列只允许任务之间传递同种数据类型的数据现在需要任务之间传递不同数据类型的数据作用对获取队列和获取信号量进行监听只要获取到其中的一个任务就会退出阻塞态队列集创建函数函数xQueueCreateSet入参长度返回值失败NULL成功队列集句柄队列集添加队列函数函数xQueueAddToSet入参队列句柄 队列集句柄返回值成功pdPASS [注意]添加到队列集内的队列处于无数据状态队列集移除队列函数函数xQueueRemoveFromSet入参队列句柄 队列集句柄返回值成功pdPASS [注意]移除出队列集内的队列处于无数据状态队列集监听函数函数xQueueSelectFromSet入参队列集句柄 阻塞时间返回值失败NULL 成功有数据的队列句柄 [注意]移除出队列集内的队列处于无数据状态事件标志组需求队列信号量事件发生时只会唤醒一个任务现在需要事件发生时唤醒所有符合条件的任务事件标志位用一个位来表示事件是否发送事件标志组定义组事件标志位的集合特点一个位表示一个事件事件含义用户自定任意中断与任务可以读写这些位任务与中断可等待某一位成立或多位同时成立注意#define configUSE_16_BIT_TICKS 0 -- 置0表示事件标志组的数据类型是uint32_t 高八位用作存储事件标志组的控制信息低二十四位表示事件事件标志组创建函数函数xEventGroupCreate入参无返回值失败NULL 成功事件标志组句柄事件标志组清除事件标志位函数函数xEventGroupClearBits入参事件标志组句柄 待清零的事件标志位返回值事件标志组设置事件标志位函数函数xEventGroupSetBits入参事件标志组句柄 待设置的事件标志位返回值事件标志组等待事件标志位函数函数xEventGroupWaitBits入参事件标志组句柄 等待的事件标志位 是否清除 是否全等 等多久事件标志组同步函数函数xEventGroupSync//start_task EventGroupHandle_t eventgroup xEventGroupCreate(); //task1 xEventGroupSetBits(eventgroup, 0x01); //按键0按下 xEventGroupSetBits(eventgroup, 0x02); //按键1按下 //task2 xEventGroupWaitBits(eventgroup, 0x01 | 0x02, pdFALSE, pdTRUE, portMAX_DELAY);任务通知区别使用队列信号量队列集事件标志组都需创建自身结构体任务之间通信这个中间结构体进行通信 使用任务通知可直接接收别人发过来的通知优劣势优势内存占用更小劣势 中断无任务控制块所有无法发送任务通知给中断 无法广播给多个任务只是和单对单任务通信定义任务的任务控制块结构体中的成员变量ulNotifiedValue就是任务通知值任务的任务通知状态#define taskNOT_WAITING_NOTIFICATION ((uint8_t)0) /* 任务未等待通知 */ #define taskWAITING_NOTIFICATION ((uint8_t)1) /* 任务在等待通知 */ #define taskNOTIFICATION_RECEIVED ((uint8_t)2) /* 任务在等待接收 */ 任务未等待通知任务通知默认的初始化状态 等待通知接收方已经准备好了调用了接收任务通知函数接收方等待发送方通知 等待接收发送方已经发送出去调用了发送任务通知函数发送方等待接收方接收任务通知值更新方式typedef enum { eNoAction 0, /* 无操作 */ eSetBits, /* 更新指定bit */ eIncrement, /* 通知值加一 */ eSetValueWithOverwrite, /* 覆写的方式更新通知值 */ eSetValueWithoutOverwrite /* 不覆写通知值 */ } eNotifyAction;任务通知发送函数xTaskNotifyGive 入参接收任务任务句柄 返回值无xTaskNotify 入参接收任务任务句柄 待发送的数据 任务通知更新方式 返回值BaseType_t任务通知接收函数ulTaskNotifyTake 入参pdTRUE/pdFALSE(任务通知值接收成功后清零/减1) 等待接收时间 返回值uint32_t(非0表示接收成功)xTaskNotifyWait 入参原先任务通知值要清除的位 等待成功后任务通知值要清除的位 传入一个地址保存接收到的任务通知值 等待时间 返回值BaseType_t任务通知模拟模拟二值信号量 xTaskNotifyGive/ulTaskNotifyTakexTaskNotifyGive(task2_handler); rev ulTaskNotifyTake(pdTRUE , portMAX_DELAY);模拟计数信号量 xTaskNotifyGive/ulTaskNotifyTakexTaskNotifyGive(task2_handler); rev ulTaskNotifyTake(pdFALSE, portMAX_DELAY);模拟队列xTaskNotify( task2_handler, key, eSetValueWithOverwrite); uint32_t noyify_val 0; xTaskNotifyWait( 0, 0xFFFFFFFF, noyify_val, portMAX_DELAY);模拟事件标志组xTaskNotify( task2_handler, EVENTBIT_0, eSetBits); xTaskNotifyWait(0, 0xFFFFFFFF, notify_val, portMAX_DELAY);