1.开发背景
基于以上的章节,了解了 FreeRTOS 多线程间的信号量、队列的使用,已经满足了日常使用场景。这个篇章要介绍的是队列集,实际上队列的升级版,存储信号量和队列等的触发事件。
队列集在实际的开发项目中应用相对比较少,事件存储在队列中,在一定程度上影响了系统的实时性,优点就是一个线程处理多种事件,减少了线程的个数,适合资源使用比较少的场景。
2.开发需求
设计实验:
1)创建 2 个线程,控制线程和接收线程
2)控制线程发送不同的信号量和队列
3)接收线程接收队列集后再获取对应的信息
3.开发环境
window10 + MDK + STM32F429 + FreeRTOS10.3.1
4.实现步骤
4.1 实现编码
#include "appTest.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "mspDwt.h"
#include "mspGpio.h"
#include "mspExti.h"
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "appLog.h"
/* #define configUSE_QUEUE_SETS 1 */
typedef struct
{
/* 信号量 */
SemaphoreHandle_t signalBinary;
SemaphoreHandle_t signalCount;
/* 队列 */
QueueHandle_t queue;
/* 队列集 */
QueueSetHandle_t queueSet;
/* 创建任务 */
TaskHandle_t taskCtrl;
TaskHandle_t taskRx;
}Ctrl_t;
/* 文件指针 */
static Ctrl_t s_ctrl = {0};
static Ctrl_t *p = &s_ctrl;
static void TaskCtrl(void *pvParameters);
static void TaskRx(void *pvParameters);
static void TaskCtrl(void *pvParameters)
{
/* 发送信号量 */
xSemaphoreGive(p->signalCount); // 1
xSemaphoreGive(p->signalBinary); // 2
xSemaphoreGive(p->signalCount); // 3
/* 发送队列 */
for (int i = 0; i < 3; i++)
{
xQueueSend(p->queue, &i, 100); // 4,5,6
}
/* 发送信号量 */
xSemaphoreGive(p->signalCount); // 7
xSemaphoreGive(p->signalCount); // 8
for ( ; ; )
{
vTaskDelay(1000);
}
}
/* 接收线程 */
static void TaskRx(void *pvParameters)
{
vTaskDelay(100);
QueueSetMemberHandle_t member = 0;
for ( ; ; )
{
/* 等待队列组触发 */
member = xQueueSelectFromSet(p->queueSet, portMAX_DELAY);
/* 解析成员句柄并提取对应的数据 */
if (member == p->signalBinary)
{
/* 接收到二值信号量 */
xSemaphoreTake(p->signalBinary, 0);
Log_Debug("%s 接收到二值信号量\r\n", __func__);
}
else if (member == p->signalCount)
{
/* 接收到计数信号量 */
xSemaphoreTake(p->signalCount, 0);
Log_Debug("%s 接收到计数信号量\r\n", __func__);
}
else if (member == p->queue)
{
/* 接收到队列 */
static unsigned int queueRx = 0;
xQueueReceive(p->queue, &queueRx, 0);
Log_Debug("%s 接收到队列, queueRx = %d\r\n", __func__, queueRx);
}
else
{
Log_Error("%s 异常 else\r\n", __func__);
}
}
}
/* 测试初始化 */
void aTest_Init(void)
{
/* 创建二值信号量 */
p->signalBinary = xSemaphoreCreateBinary();
/* 创建计数信号量 */
UBaseType_t uxMaxCount = 5;
p->signalCount = xSemaphoreCreateCounting(uxMaxCount, 0);
/* 创建队列 */
UBaseType_t uxQueueLength = 10;
UBaseType_t uxItemSize = sizeof(unsigned int);
p->queue = xQueueCreate(uxQueueLength, uxItemSize);
/* 创建队列集 二值信号量=1,计数信号量=最大计数值 队列=队长 */
UBaseType_t uxEventQueueLength = 1 + uxMaxCount + uxQueueLength;
p->queueSet = xQueueCreateSet(uxEventQueueLength);
/* 添加成员到队列集 */
xQueueAddToSet(p->signalBinary, p->queueSet);
xQueueAddToSet(p->signalCount, p->queueSet);
xQueueAddToSet(p->queue, p->queueSet);
/* 创建动态任务 */
xTaskCreate(TaskCtrl, "TaskCtrl", 500, NULL, 4, &p->taskCtrl);
xTaskCreate(TaskRx, "TaskRx", 500, NULL, 4, &p->taskRx);
}
/* Key2 PC13 Key0 PH3 Key1 PH2 */
void Exti13_TriggerInterrupt(void)
{
mspExti_Close(13);
if (mspGpio_GetInput("PC13") == 0)
{
}
}
在使用 uxEventQueueLength 的时候需要特别注意,
/* 创建二值信号量 */
p->signalBinary = xSemaphoreCreateBinary();
/* 创建计数信号量 */
UBaseType_t uxMaxCount = 5;
p->signalCount = xSemaphoreCreateCounting(uxMaxCount, 0);
/* 创建队列 */
UBaseType_t uxQueueLength = 10;
UBaseType_t uxItemSize = sizeof(unsigned int);
p->queue = xQueueCreate(uxQueueLength, uxItemSize);
/* 创建队列集 二值信号量=1,计数信号量=最大计数值 队列=队长 */
UBaseType_t uxEventQueueLength = 1 + uxMaxCount + uxQueueLength;
p->queueSet = xQueueCreateSet(uxEventQueueLength);
/* 添加成员到队列集 */
xQueueAddToSet(p->signalBinary, p->queueSet);
xQueueAddToSet(p->signalCount, p->queueSet);
xQueueAddToSet(p->queue, p->queueSet);