河南网站排名优化,免费网页空间到哪申请,工程建设专业,西安商城网站制作1. FreeRTOS 消息队列
1.1 简介
队列是 任务间通信的主要形式#xff0c;可用于在任务之间以及中断与任务之间传递消息。队列在 FreeRTOS 中具有以下关键特点#xff1a;
队列默认采用 先进先出 FIFO 方式#xff0c;也可以使用 xQueueSendToFront()实现 LIFO。FreeRT…1. FreeRTOS 消息队列
1.1 简介
队列是 任务间通信的主要形式可用于在任务之间以及中断与任务之间传递消息。队列在 FreeRTOS 中具有以下关键特点
队列默认采用 先进先出 FIFO 方式也可以使用 xQueueSendToFront()实现 LIFO。FreeRTOS 确保队列操作是原子的不会因为任务切换而导致数据损坏。如果队列 满了写入时或 空了读取时任务 可以选择阻塞等待消息 或 非阻塞立即返回。高优先级任务更快地执行队列操作如果多个任务在相同优先级按照 时间片轮转 处理队列。消息大小固定但可以存储指向可变数据的指针。
1.2 队列相关 API 函数介绍
FreeRTOS 队列管理 API 速览
1. 队列的创建 API
API 函数描述xQueueCreate()动态创建队列xQueueCreateStatic()静态创建队列
2. 队列消息的写入 API
API 函数描述xQueueSend()往队列尾部写入消息xQueueSendToBack()同 xQueueSend()往队列尾部写入消息xQueueSendToFront()往队列头部写入消息xQueueOverwrite()覆写队列消息仅限队列长度为 1xQueueSendFromISR()在中断中往队列尾部写入消息xQueueSendToBackFromISR()同 xQueueSendFromISR()往队列尾部写入xQueueSendToFrontFromISR()在中断中往队列头部写入消息xQueueOverwriteFromISR()在中断中覆写队列消息仅限队列长度为 1
3. 队列消息的读取 API
API 函数描述xQueueReceive()从队列头部读取消息并删除消息xQueuePeek()从队列头部读取消息但不删除xQueueReceiveFromISR()在中断中从队列头部读取消息并删除消息xQueuePeekFromISR()在中断中从队列头部读取消息但不删除
1.3 实验
start_task用来创建其他的 3 个任务。task1当按键 key1 或 key2 按下将键值拷贝到队列 queue1入队当按键 key3 按下将传输大数据这里拷贝大数据的地址到队列 big_queue 中。task2读取队列 queue1 中的消息出队打印出接收到的键值。task3从队列 big_queue 读取大数据地址通过地址访问大数据。
1 ) 创建队列程序
QueueHandle_t queue1; /* 小数据句柄 */
QueueHandle_t big_queue; /* 大数据句柄 */
char buff[100] {dioajdiaj fdahjk324hjkhfjksdahjk#$!#jfaskdfhjka};void task_start(void *pvParameters)
{/* 进入临界区:保护临界区里的代码不会被打断 */taskENTER_CRITICAL();/* 创建 queue1 队列 */queue1 xQueueCreate(2, sizeof(uint8_t));if (queue1 ! NULL){printf(queue1 队列创建成功\r\n);}else{printf(queue1 队列创建失败\r\n);}/* 创建 big_queue 队列 */big_queue xQueueCreate(1, sizeof(char *));if (big_queue ! NULL){printf(big_queue 队列创建成功\r\n);}else{printf(big_queue 队列创建失败\r\n);}/* 创建三个任务 */xTaskCreate((TaskFunction_t)task1,(char *)task1,(configSTACK_DEPTH_TYPE)TASK1_STACK_SIZE,(void *)NULL,(UBaseType_t)TASK1_PRIORITY,(TaskHandle_t *)Task1_Handler);xTaskCreate((TaskFunction_t)task2,(char *)task2,(configSTACK_DEPTH_TYPE)TASK2_STACK_SIZE,(void *)NULL,(UBaseType_t)TASK2_PRIORITY,(TaskHandle_t *)Task2_Handler);xTaskCreate((TaskFunction_t)task3,(char *)task3,(configSTACK_DEPTH_TYPE)TASK3_STACK_SIZE,(void *)NULL,(UBaseType_t)TASK3_PRIORITY,(TaskHandle_t *)Task3_Handler);/* 启动任务只需要执行一次即可用完就删除自己 */vTaskDelete(NULL);/* 退出临界区 */taskEXIT_CRITICAL();
}2 ) task1
void task1(void *pvParameters)
{uint8_t key_value 0;char *buf;BaseType_t err 0;buf buff[0];char task_info[200];while (1){if (key[0].flag 1 || key[1].flag 1){key_value key[0].flag;err xQueueSendToBack(queue1, key_value, portMAX_DELAY);if (err ! pdTRUE){printf(queue1 队列发送失败\r\n);}key[0].flag 0;key[1].flag 0;}else if (key[2].flag 1){err xQueueSendToBack(big_queue, buf, portMAX_DELAY);if (err ! pdTRUE){printf(big_queue 队列发送失败\r\n);}key[2].flag 0;}}
}3 ) task2
void task2(void *pvParameters)
{uint8_t key 0;BaseType_t err 0;while (1){err xQueueReceive(queue1, key, portMAX_DELAY);if (err ! pdTRUE){printf(queue1 队列读取失败\r\n);}else{printf(queue1 读取队列成功数据%d\r\n, key);}}
}4 ) task3
void task3(void *pvParameters)
{char *buf;BaseType_t err 0;while (1){for (int i 0; i 16; i){if (key[i].flag 1){err xQueueReceive(big_queue, buf, portMAX_DELAY);if (err ! pdTRUE){printf(big_queue 队列读取失败\r\n);}else{printf(data:%s\r\n, buf);}}}}
}2. FreeRTOS 队列集
队列集Queue Set是 FreeRTOS 中的一种数据结构用于管理多个队列。它提供了一种有效的方式通过单个 API 调用来操作和访问一组相关的队列。在多任务系统中任务之间可能需要共享数据而这些数据可能存储在不同的队列中。队列集的作用就是为了更方便地管理这些相关队列使得任务能够轻松地访问和处理多个队列的数据。
2.1 队列集相关 API 函数介绍
函数描述xQueueCreateSet()创建队列集用于管理多个队列或信号量xQueueAddToSet()向队列集添加队列或信号量xQueueRemoveFromSet()从队列集中移除队列或信号量xQueueSelectFromSet()获取队列集中有消息的队列阻塞xQueueSelectFromSetFromISR()在中断中获取队列集中有消息的队列非阻塞
2.2 实验
start_task用来创建其他 2 个任务并创建队列集、俩个队列将这俩个队列添加到队列集中。task1用于扫描按键当 KEY1 按下往队列1中写入数据当 KEY2 按下往队列2中写入数据。task2读取队列集中的消息并打印。
1 ) 创建队列集
QueueHandle_t queue1, queue2;
QueueSetHandle_t queue_set;void task_start(void *pvParameters)
{/* 进入临界区:保护临界区里的代码不会被打断 */taskENTER_CRITICAL();/* 创建 queue1 队列 */queue1 xQueueCreate(1, sizeof(uint8_t));if (queue1 ! NULL){printf(queue1 队列创建成功\r\n);}else{printf(queue1 队列创建失败\r\n);}/* 创建 queue2 队列 */queue2 xQueueCreate(1, sizeof(char *));if (queue2 ! NULL){printf(queue2 队列创建成功\r\n);}else{printf(queue2 队列创建失败\r\n);}/* 创建 queue2 队列 */queue_set xQueueCreateSet(2);if (queue_set ! NULL){printf(queue_set 队列创建成功\r\n);}else{printf(queue_set 队列创建失败\r\n);}xQueueAddToSet(queue1, queue_set);xQueueAddToSet(queue2, queue_set);/* 创建任务 */xTaskCreate((TaskFunction_t)task1,(char *)task1,(configSTACK_DEPTH_TYPE)TASK1_STACK_SIZE,(void *)NULL,(UBaseType_t)TASK1_PRIORITY,(TaskHandle_t *)Task1_Handler);xTaskCreate((TaskFunction_t)task2,(char *)task2,(configSTACK_DEPTH_TYPE)TASK2_STACK_SIZE,(void *)NULL,(UBaseType_t)TASK2_PRIORITY,(TaskHandle_t *)Task2_Handler);/* 启动任务只需要执行一次即可用完就删除自己 */vTaskDelete(NULL);/* 退出临界区 */taskEXIT_CRITICAL();
}2 ) task1:
void task1(void *pvParameters)
{char *buf;char text[20];BaseType_t err 0;while (1){if (key[0].flag 1){sprintf((char *)text, queue1 数据);buf text[0];err xQueueSendToBack(queue1, buf, portMAX_DELAY);if (err ! pdTRUE){printf(queue1 队列写入数据错误\r\n);}key[0].flag 0;}else if (key[1].flag 1){sprintf((char *)text, queue2 数据);buf text[0];err xQueueSendToBack(queue2, buf, portMAX_DELAY);if (err ! pdTRUE){printf(queue2 队列写入数据错误\r\n);}key[1].flag 0;}vTaskDelay(100);}
}3 ) task2:
void task2(void *pvParameters)
{char *buf;QueueSetMemberHandle_t queue NULL;while (1){queue xQueueSelectFromSet(queue_set, portMAX_DELAY);if (queue queue1){xQueueReceive(queue, buf, portMAX_DELAY);printf(queue1 读取到数据为: %s\r\n, buf);}if (queue queue2){xQueueReceive(queue, buf, portMAX_DELAY);printf(queue2 读取到数据为: %s\r\n, buf);}vTaskDelay(100);}
}3. FreeRTOS 信号量
3.1 简介
信号量Semaphore是一种用于 任务同步 或 任务间资源互斥 的机制主要用于
任务同步协调任务之间的执行顺序如等待某个事件发生后再执行任务。互斥访问保护共享资源防止多个任务同时访问而引起竞争问题。
FreeRTOS 提供了 二值信号量、计数信号量 和 互斥信号量 三种类型
信号量类型作用二值信号量Binary Semaphore只能取 0 或 1常用于任务同步或简单的互斥访问计数信号量Counting Semaphore可取多个值适用于多个资源的同步管理互斥信号量Mutex具备 优先级继承 机制主要用于任务间的互斥访问
3.2 常用 API 函数
API 函数作用xSemaphoreCreateBinary()创建二值信号量初始值为 0需要 xSemaphoreGive() 释放一次后才能使用xSemaphoreCreateBinaryStatic()使用静态方式创建二值信号量xSemaphoreCreateCounting()创建计数信号量xSemaphoreCreateMutex()创建互斥信号量xSemaphoreGive()释放信号量1xSemaphoreTake()获取信号量-1如果没有可用信号量则阻塞uxSemaphoreGetCount()获取信号量的计数值xSemaphoreGiveFromISR()在中断中释放信号量xSemaphoreTakeFromISR()在中断中获取信号量
信号量 API 函数允许指定阻塞时间。 阻塞时间表示当一个任务试图“获取”信号量时如果信号不是立即可用那么该任务进入阻塞状态的最大 “tick” 数。 如果多个任务在同一个信号量上阻塞那么具有最高优先级的任务将在下次信号量可用时最先解除阻塞 。 在 FreeRTOS 中信号量 实际上是一个特殊的队列本质上 创建信号量就是创建一个只存储一个元素的队列区别在于 二值信号量Binary Semaphore队列长度固定为 1每次只能存储 一个项目用于 任务同步。计数信号量Counting Semaphore队列长度可以大于 1用于 多个资源的管理。互斥信号量Mutex基于二值信号量但增加了 优先级继承 机制用于资源互斥 对于二值信号量 FreeRTOS 通过 xQueueGenericCreate() 这个通用队列创建函数来创建信号量但是这个函数在 semphr.h 被宏定义为 /*
(UBaseType_t) 1 → 队列长度 1二值信号量只能存储一个信号量
semSEMAPHORE_QUEUE_ITEM_LENGTH → 项目大小 0不存储实际数据仅表示可用信号量
queueQUEUE_TYPE_BINARY_SEMAPHORE → 队列类型 信号量队列
*/
#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )信号量的作用本质是管理这个队列是否为空。 而计数信号量创建函数等效为 /*
uxMaxCount → 队列长度 计数信号量可以为任何整数
queueSEMAPHORE_QUEUE_ITEM_LENGTH → 项目大小 0不存储实际数据仅表示可用信号量
queueQUEUE_TYPE_BINARY_SEMAPHORE → 队列类型 信号量队列
*/
xQueueGenericCreate( uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_COUNTING_SEMAPHORE );互斥信号量创建函数等效为 /*
uxMutexLength 1 → 队列长度 1互斥信号量只能存储一个信号量
uxMutexSize → 项目大小 0不存储实际数据仅表示可用信号量
queueQUEUE_TYPE_MUTEX → 队列类型 信号量队列
*/
xQueueGenericCreate( uxMutexLength, uxMutexSize, queueQUEUE_TYPE_MUTEX )3.3 实验
3.3.1 二值信号量实验
start_task用来创建其他的 2 个任务。task1用于按键扫描当检测到按键 KEY1 被按下时释放二值信号量。task2获取二值信号量当成功获取后打印提示信息。
1 ) 创建二值信号量
QueueHandle_t semaphore_handle;void task_start(void *pvParameters)
{/* 进入临界区:保护临界区里的代码不会被打断 */taskENTER_CRITICAL();/* 创建信号量 */semaphore_handle xSemaphoreCreateBinary();if (semaphore_handle ! NULL){printf(二值信号量创建成功\r\n);}else{printf(二值信号量创建失败\r\n);}/* 创建任务 */xTaskCreate((TaskFunction_t)task1,(char *)task1,(configSTACK_DEPTH_TYPE)TASK1_STACK_SIZE,(void *)NULL,(UBaseType_t)TASK1_PRIORITY,(TaskHandle_t *)Task1_Handler);xTaskCreate((TaskFunction_t)task2,(char *)task2,(configSTACK_DEPTH_TYPE)TASK2_STACK_SIZE,(void *)NULL,(UBaseType_t)TASK2_PRIORITY,(TaskHandle_t *)Task2_Handler);/* 启动任务只需要执行一次即可用完就删除自己 */vTaskDelete(NULL);/* 退出临界区 */taskEXIT_CRITICAL();
}2 ) task1:
void task1(void *pvParameters)
{BaseType_t err;while (1){if (key[0].flag 1){err xSemaphoreGive(semaphore_handle);if (err ! pdTRUE){printf(释放信号量失败\r\n);}led[0].state !led[0].state;HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, (GPIO_PinState)led[0].state);key[0].flag 0;}}
}3 ) task2:
void task2(void *pvParameters)
{BaseType_t err 0;while (1){err xSemaphoreTake(semaphore_handle,portMAX_DELAY);if (err ! pdTRUE){printf(获取信号量失败\r\n);}else{printf(成功获取信号量\r\n);}}
}3.3 .2 计数信号量实验
start_task用来创建其他的 2 个任务。task1用于按键扫描当检测到按键 KEY1 被按下时释放计数型信号量。task2每过一秒获取一次计数型信号量当成功获取后打印信号量计数值。
1 ) 创建计数信号量
QueueHandle_t semaphore_handle;void task_start(void *pvParameters)
{/* 进入临界区:保护临界区里的代码不会被打断 */taskENTER_CRITICAL();/* 创建计数信号量 */UBaseType_t uxMaxCount 4;UBaseType_t uxInitialCount 0;semaphore_handle xSemaphoreCreateCounting(uxMaxCount,uxInitialCount);if (semaphore_handle ! NULL){printf(计数信号量创建成功\r\n);}else{printf(计数信号量创建失败\r\n);}/* 创建任务 */xTaskCreate((TaskFunction_t)task1,(char *)task1,(configSTACK_DEPTH_TYPE)TASK1_STACK_SIZE,(void *)NULL,(UBaseType_t)TASK1_PRIORITY,(TaskHandle_t *)Task1_Handler);xTaskCreate((TaskFunction_t)task2,(char *)task2,(configSTACK_DEPTH_TYPE)TASK2_STACK_SIZE,(void *)NULL,(UBaseType_t)TASK2_PRIORITY,(TaskHandle_t *)Task2_Handler);/* 启动任务只需要执行一次即可用完就删除自己 */vTaskDelete(NULL);/* 退出临界区 */taskEXIT_CRITICAL();
}2 ) task1:
void task1(void *pvParameters)
{BaseType_t err;while (1){if (key[0].flag 1){err xSemaphoreGive(semaphore_handle);if (err ! pdTRUE){printf(释放信号量失败\r\n);}else{printf(释放信号量\r\n);}led[0].state !led[0].state;HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, (GPIO_PinState)led[0].state);key[0].flag 0;}}
}3 ) task2:
void task2(void *pvParameters)
{BaseType_t err 0;while (1){if(uxSemaphoreGetCount(semaphore_handle) ! 0){err xSemaphoreTake(semaphore_handle,portMAX_DELAY);if (err ! pdTRUE){printf(获取信号量失败\r\n);}else{printf(成功获取信号量\r\n);}}else{printf(无空闲资源分配\r\n);}vTaskDelay(1000);}
}3.4 任务优先级翻转 bug 问题
优先级翻转是一个在实时系统中可能出现的问题特别是在多任务环境中。该问题指的是一个较低优先级的任务阻塞了一个较高优先级任务的执行从而导致高优先级任务无法及时完成。
典型的优先级翻转场景如下
任务 A高优先级拥有高优先级需要访问共享资源比如一个关键数据结构。任务 B低优先级拥有低优先级目前正在访问该共享资源。任务 C中优先级位于任务 A 和任务 B 之间具有介于两者之间的优先级。
具体流程如下
1任务 A 开始执行但由于任务 B 正在访问共享资源任务 A 被阻塞等待。
2任务 C 获得执行权由于优先级高于任务 B它可以抢占任务 B。
3任务 C 执行完成后任务 B 被解除阻塞开始执行完成后释放了共享资源。
4任务 A 重新获取执行权继续执行。
这个过程中任务 A 因为资源被占用而被阻塞而任务 B 却被中优先级的任务 C 抢占导致任务 B 无法及时完成。这种情况称为优先级翻转因为任务 C 的介入翻转了高优先级任务 A 的执行顺序。
实验模拟
模拟优先级翻转观察对抢占式内核的影响
start_task用来创建其他的 3 个任务。task1低优先级任务同高优先级一样的操作不同的是低优先级任务占用信号task2中等优先级任务简单的应用任务。task3高优先级任务会获取二值信号量获取成功以后打印提示信息处理完后释放信号量。
1 ) 创建队列程序
QueueHandle_t semaphore_handle;/*** brief : 启动任务函数创建三个任务并删除自己** param pvParameters*/
void task_start(void *pvParameters)
{/* 进入临界区:保护临界区里的代码不会被打断 */taskENTER_CRITICAL();/* 创建计数信号量 */UBaseType_t uxMaxCount 1;UBaseType_t uxInitialCount 1;semaphore_handle xSemaphoreCreateCounting(uxMaxCount, uxInitialCount);if (semaphore_handle ! NULL){printf(计数信号量创建成功\r\n);}else{printf(计数信号量创建失败\r\n);}/* 创建三个任务 */xTaskCreate((TaskFunction_t)task1,(char *)task1,(configSTACK_DEPTH_TYPE)TASK1_STACK_SIZE,(void *)NULL,(UBaseType_t)TASK1_PRIORITY,(TaskHandle_t *)Task1_Handler);xTaskCreate((TaskFunction_t)task2,(char *)task2,(configSTACK_DEPTH_TYPE)TASK2_STACK_SIZE,(void *)NULL,(UBaseType_t)TASK2_PRIORITY,(TaskHandle_t *)Task2_Handler);xTaskCreate((TaskFunction_t)task3,(char *)task3,(configSTACK_DEPTH_TYPE)TASK3_STACK_SIZE,(void *)NULL,(UBaseType_t)TASK3_PRIORITY,(TaskHandle_t *)Task3_Handler);/* 启动任务只需要执行一次即可用完就删除自己 */vTaskDelete(NULL);/* 退出临界区 */taskEXIT_CRITICAL();
}2 ) task1
void task1(void *pvParameters)
{while (1){printf(低优先级 Task1 获取信号量\r\n);xSemaphoreTake(semaphore_handle, portMAX_DELAY);printf(低优先级 Task1 正在运行\r\n);HAL_Delay(3000);printf(低优先级 Task1 释放信号量\r\n);xSemaphoreGive(semaphore_handle);vTaskDelay(1000);}
}3 ) task2
void task2(void *pvParameters)
{while (1){printf(中优先级的 Task2 正在执行\r\n);HAL_Delay(1500);printf(Task2 执行完成一次.....\r\n);vTaskDelay(1000);}
}4 ) task3
void task3(void *pvParameters)
{while (1){printf(高优先级 Task3 获取信号量\r\n);xSemaphoreTake(semaphore_handle, portMAX_DELAY);printf(高优先级 Task3 正在运行\r\n);HAL_Delay(1000);printf(高优先级 Task3 释放信号量\r\n);xSemaphoreGive(semaphore_handle);vTaskDelay(1000);}
}5 ) 实验结果 可以观察到 Task1 获取信号量后Task2 通过抢占 Task1 实现了翻转优先级实现了优于 Task3 的执行优先。
3.5 互斥信号量
互斥信号量是包含优先级继承机制的二进制信号量。二进制信号量能更好实现同步任务间或任务与中断之间 而互斥信号量有助于更好实现简单互斥即相互排斥。优先级继承是一种解决实时系统中任务调度引起的优先级翻转问题的机制。在具体的任务调度中当一个高优先级任务等待一个低优先级任务所持有的资源时系统会提升低优先级任务的优先级以避免高优先级任务长时间等待的情况。 互斥信号量的获取和释放函数与二值信号量的相应函数相似但有一个重要的区别互斥信号量不支持在中断服务程序中直接调用。注意当创建互斥信号量时系统会自动进行一次信号量的释放操作。 通过互斥信号量来解决优先级翻转实验
1 ) 将二值信号量改为互斥信号量 semaphore_handle xSemaphoreCreateMutex();if (semaphore_handle ! NULL){printf(互斥信号量创建成功\r\n);}else{printf(互斥信号量创建失败\r\n);}2 ) 实验结果
可以观察到 Task2 只能在 Task3 信号量释放的后才可以抢占运行不会发生任务优先级的翻转在 Task1 释放信号量后 Task2 立马抢占执行而是 Task3 立刻占用信号量开始执行 Task3 再执行 Task2
4. FreeRTOS 事件标志组
4.1 简介
事件标志组Event Groups是 FreeRTOS 提供的一种轻量级任务间同步机制允许任务或中断通过 设置或清除 “事件标志Event Bits” 来实现 事件通知、同步和状态监控。事件标志组类似于 二进制标志位集合每个标志位可以单独操作多个任务可以等待多个标志位满足特定条件后再执行。
事件标志组特点
每个事件标志组是一个 8/24 位独立的二进制标志位Event Bits。任务可以等待多个事件标志位并指定所有满足或任意一个满足时触发任务执行。事件标志位可由任务或中断设置/清除支持 ISR 操作。比队列Queue和信号量Semaphore更高效适用于简单事件同步。
事件标志组的适用场景
应用场景适合事件标志组适合队列或信号量多任务同步✔️ 多任务需要等待某些事件发生❌中断通知任务✔️ 事件触发后可直接通知多个任务✔️ 但队列或信号量只能通知一个任务状态监测✔️ 可使用不同事件位表示不同状态❌任务间数据传输❌✔️ 队列适合传输数据
事件标志组和信号量都是 FreeRTOS 中用于任务同步和通信的机制但它们适用于不同的场景主要区别如下
对比项事件标志组Event Flags Group信号量Semaphore用途用于任务间事件通知和同步标志位代表某个事件状态用于任务间资源控制和同步确保安全访问共享资源状态表示每个标志位只有 已设置/未设置 两种状态信号量是一个计数器可用于 计数、互斥、同步任务等待任务可等待 多个事件同时满足 或 任意一个事件发生任务等待信号量计数变为 非零然后继续执行适用场景适用于任务间 事件同步如 数据准备完成、状态变更通知适用于 资源访问控制、同步、互斥防止多个任务同时访问共享资源信号传递可存储多个事件状态即使任务不在等待事件状态仍然保留不可存储状态如果任务未在等待信号量会直接丢失示例任务 A 设置事件标志 → 任务 B 等待该事件标志并继续执行任务 A 释放信号量 → 任务 B 获取信号量并访问共享资源
4.2 事件标志组和事件位数据类型
可以将事件组视为一个二进制标志集合其中的每一位表示一个事件。任务可以设置Set、清Clear或等待Wait某些特定的事件位从而实现任务间的 同步与信号触发。事件组的大小即支持的 事件位数受 FreeRTOS 配置项的影响由 configUSE_16_BIT_TICKS 控制
#define configUSE_16_BIT_TICKS 1 // 事件组内可用标志数位为8
#define configUSE_16_BIT_TICKS 0 // 事件组内可用标志数位为24 在 FreeRTOS 中事件组的最大位数 由 EventBits_t 变量的大小决定而 EventBits_t 的大小受 TickType_t用于计时的变量类型影响。所以最高为32位但是 FreeRTOS 保留了 8 位 供系统内部使用
4.3 事件标志组相关 API 函数介绍
API 函数功能xEventGroupCreate()创建事件标志组xEventGroupCreateStatic()使用静态地创建事件标志组xEventGroupSetBits()设置一个或多个事件标志位xEventGroupClearBits()清除一个或多个事件标志位xEventGroupWaitBits()等待一个或多个事件标志位被置位xEventGroupGetBits()获取当前事件标志状态xEventGroupSetBitsFromISR()在中断中设置事件标志位vEventGroupDelete()删除事件标志组xEventGroupSync()多个任务同步等待所有事件标志
4.4 实验
start_task用来创建其他 3 个任务并创建事件标志组。task1读取按键按下键值根据不同键值将事件标志组相应事件位置一模拟事件发生。task2同时等待事件标志组中的多个事件位当这些事件位都置 1 的话就执行相应的处理。task3等待事件标志组中的多个任一事件位当这些事件位任意置 1 的话就执行相应的处理。
1 ) 创建事件标志组程序
EventGroupHandle_t event_group;/*** brief : 启动任务函数创建三个任务并删除自己** param pvParameters*/
void task_start(void *pvParameters)
{/* 进入临界区:保护临界区里的代码不会被打断 */taskENTER_CRITICAL();/* 创建事件标志组 */event_group xEventGroupCreate();if (event_group NULL){printf(事件标志组创建失败\r\n);}else{printf(事件标志组创建成功\r\n);}/* 创建任务 */xTaskCreate((TaskFunction_t)task1,(char *)task1,(configSTACK_DEPTH_TYPE)TASK1_STACK_SIZE,(void *)NULL,(UBaseType_t)TASK1_PRIORITY,(TaskHandle_t *)Task1_Handler);xTaskCreate((TaskFunction_t)task2,(char *)task2,(configSTACK_DEPTH_TYPE)TASK2_STACK_SIZE,(void *)NULL,(UBaseType_t)TASK2_PRIORITY,(TaskHandle_t *)Task2_Handler);xTaskCreate((TaskFunction_t)task3,(char *)task3,(configSTACK_DEPTH_TYPE)TASK3_STACK_SIZE,(void *)NULL,(UBaseType_t)TASK3_PRIORITY,(TaskHandle_t *)Task3_Handler);/* 启动任务只需要执行一次即可用完就删除自己 */vTaskDelete(NULL);/* 退出临界区 */taskEXIT_CRITICAL();
}2 ) task1:
void task1(void *pvParameters)
{while (1){if (key[0].flag 1){xEventGroupSetBits(event_group, 0x01 0);printf(事件0置位\r\n);key[0].flag 0;}else if (key[1].flag 1){xEventGroupSetBits(event_group, 0x01 1);printf(事件1置位\r\n);key[1].flag 0;}else if (key[2].flag 1){xEventGroupSetBits(event_group, 0x01 2);printf(事件2置位\r\n);key[2].flag 0;}else if (key[3].flag 1){xEventGroupSetBits(event_group, 0x01 3);printf(事件3置位\r\n);key[3].flag 0;}vTaskDelay(100);}
}3 ) task2:
void task2(void *pvParameters)
{while (1){xEventGroupWaitBits(event_group, 1 0 | 1 1, pdTRUE, pdTRUE, portMAX_DELAY);printf(事件0和1同时有效执行task2...\r\n);vTaskDelay(100);}
}4 ) task3:
void task3(void *pvParameters)
{while (1){xEventGroupWaitBits(event_group, 1 2 | 1 3, pdTRUE, pdFALSE, portMAX_DELAY);printf(事件2和3任一有效执行task3...\r\n);vTaskDelay(100);}
}
文章转载自: http://www.morning.jppdk.cn.gov.cn.jppdk.cn http://www.morning.mkhwx.cn.gov.cn.mkhwx.cn http://www.morning.rkwlg.cn.gov.cn.rkwlg.cn http://www.morning.qpnb.cn.gov.cn.qpnb.cn http://www.morning.kscwt.cn.gov.cn.kscwt.cn http://www.morning.qnypp.cn.gov.cn.qnypp.cn http://www.morning.jypsm.cn.gov.cn.jypsm.cn http://www.morning.bwmq.cn.gov.cn.bwmq.cn http://www.morning.pyxwn.cn.gov.cn.pyxwn.cn http://www.morning.cyfsl.cn.gov.cn.cyfsl.cn http://www.morning.rksnk.cn.gov.cn.rksnk.cn http://www.morning.knsmh.cn.gov.cn.knsmh.cn http://www.morning.jntcr.cn.gov.cn.jntcr.cn http://www.morning.lhptg.cn.gov.cn.lhptg.cn http://www.morning.mpflb.cn.gov.cn.mpflb.cn http://www.morning.lwlnw.cn.gov.cn.lwlnw.cn http://www.morning.wlstn.cn.gov.cn.wlstn.cn http://www.morning.qhydkj.com.gov.cn.qhydkj.com http://www.morning.jwncx.cn.gov.cn.jwncx.cn http://www.morning.njftk.cn.gov.cn.njftk.cn http://www.morning.xznrk.cn.gov.cn.xznrk.cn http://www.morning.twwzk.cn.gov.cn.twwzk.cn http://www.morning.ptxwg.cn.gov.cn.ptxwg.cn http://www.morning.c7627.cn.gov.cn.c7627.cn http://www.morning.wwkdh.cn.gov.cn.wwkdh.cn http://www.morning.ckwrn.cn.gov.cn.ckwrn.cn http://www.morning.syssdz.cn.gov.cn.syssdz.cn http://www.morning.newfeiya.com.cn.gov.cn.newfeiya.com.cn http://www.morning.lbfgq.cn.gov.cn.lbfgq.cn http://www.morning.ybshj.cn.gov.cn.ybshj.cn http://www.morning.ymfzd.cn.gov.cn.ymfzd.cn http://www.morning.yznsx.cn.gov.cn.yznsx.cn http://www.morning.qmpbs.cn.gov.cn.qmpbs.cn http://www.morning.sjpht.cn.gov.cn.sjpht.cn http://www.morning.dkslm.cn.gov.cn.dkslm.cn http://www.morning.mtrz.cn.gov.cn.mtrz.cn http://www.morning.cfynn.cn.gov.cn.cfynn.cn http://www.morning.jcfqg.cn.gov.cn.jcfqg.cn http://www.morning.xymkm.cn.gov.cn.xymkm.cn http://www.morning.xgmf.cn.gov.cn.xgmf.cn http://www.morning.swimstaracademy.cn.gov.cn.swimstaracademy.cn http://www.morning.gftnx.cn.gov.cn.gftnx.cn http://www.morning.fsnhz.cn.gov.cn.fsnhz.cn http://www.morning.prmyx.cn.gov.cn.prmyx.cn http://www.morning.jfxth.cn.gov.cn.jfxth.cn http://www.morning.tbjtp.cn.gov.cn.tbjtp.cn http://www.morning.bcnsl.cn.gov.cn.bcnsl.cn http://www.morning.mlnzx.cn.gov.cn.mlnzx.cn http://www.morning.ttaes.cn.gov.cn.ttaes.cn http://www.morning.ngjpt.cn.gov.cn.ngjpt.cn http://www.morning.zwckz.cn.gov.cn.zwckz.cn http://www.morning.thbkc.cn.gov.cn.thbkc.cn http://www.morning.yqjjn.cn.gov.cn.yqjjn.cn http://www.morning.mtyhk.cn.gov.cn.mtyhk.cn http://www.morning.ymbqr.cn.gov.cn.ymbqr.cn http://www.morning.bxbnf.cn.gov.cn.bxbnf.cn http://www.morning.chehb.com.gov.cn.chehb.com http://www.morning.fyglr.cn.gov.cn.fyglr.cn http://www.morning.kfclh.cn.gov.cn.kfclh.cn http://www.morning.cwgn.cn.gov.cn.cwgn.cn http://www.morning.dplmq.cn.gov.cn.dplmq.cn http://www.morning.cbpmq.cn.gov.cn.cbpmq.cn http://www.morning.jnhhc.cn.gov.cn.jnhhc.cn http://www.morning.fhykt.cn.gov.cn.fhykt.cn http://www.morning.iuibhkd.cn.gov.cn.iuibhkd.cn http://www.morning.yqkxr.cn.gov.cn.yqkxr.cn http://www.morning.zpnfc.cn.gov.cn.zpnfc.cn http://www.morning.fengnue.com.gov.cn.fengnue.com http://www.morning.rqjl.cn.gov.cn.rqjl.cn http://www.morning.rxrw.cn.gov.cn.rxrw.cn http://www.morning.rpms.cn.gov.cn.rpms.cn http://www.morning.xqxlb.cn.gov.cn.xqxlb.cn http://www.morning.vibwp.cn.gov.cn.vibwp.cn http://www.morning.wfyzs.cn.gov.cn.wfyzs.cn http://www.morning.srxhd.cn.gov.cn.srxhd.cn http://www.morning.kpxzq.cn.gov.cn.kpxzq.cn http://www.morning.rsnd.cn.gov.cn.rsnd.cn http://www.morning.ysbrz.cn.gov.cn.ysbrz.cn http://www.morning.kzhgy.cn.gov.cn.kzhgy.cn http://www.morning.xnlj.cn.gov.cn.xnlj.cn