3、结合STM32CubeMX学习FreeRTOS实时操作系统——队列

目录

前言

1、FreeRTOS队列核心概念与特性

2、队列的常用函数API

3、队列的创建和常见配置

4、在任务中使用队列

[5、如果这篇文章能帮助到你,请点个赞鼓励一下吧ξ( ✿>◡❛)~](#5、如果这篇文章能帮助到你,请点个赞鼓励一下吧ξ( ✿>◡❛)~)


前言

之前的文章已经介绍了《如何使用STM32CubeMX在项目中添加FreeRTOS操作系统》和《FreeRTOS任务的创建和使用》,本文开始介绍FreeRTOS中队列相关的知识。

1、FreeRTOS队列核心概念与特性

FreeRTOS队列(Queue)是任务间通信的基础组件,使用队列可以在一个任务中获取数据(例如传感器数据),在另一个或多个任务中处理数据,实现线程安全的数据传输,队列具有以下核心特性:

特性 说明
​****先进先出(FIFO) 数据按发送顺序排列,最早入队的数据最先被读取
​****线程安全 提供互斥保护,允许多任务并发访问无需额外同步
​****阻塞机制 当队列空/满时,任务可选择等待数据/空间可用
​ISR****支持 通过FromISR后缀API支持中断服务程序操作
​****多数据类型 支持传输值类型(struct/uint等)或指针类型(void*)
​****可配置深度 创建时指定可存储的最大项目数量(1~65535)

2、队列的常用函数API

操作 API 函数 参数说明 返回值
​****发送数据 xQueueSend() 尾部添加,阻塞等待空间 pdPASS/pdFAIL
​****紧急发送 xQueueSendToFront() 头部插入(插队) 同上
​****覆盖发送 xQueueOverwrite() 队列满时覆盖最旧数据 总是成功
​****接收数据 xQueueReceive() 头部取出并移除数据 pdPASS/pdFAIL
​****查看数据 xQueuePeek() 头部查看但不移除数据 同上

如果在中断程序中使用队列的话需要使用特定的带尾缀FromISR的函数,可以保证在中断函数中安全的进行队列操作。如下所示:

cpp 复制代码
BaseType_t xQueueSendFromISR(QueueHandle_t xQueue,

                             const void *pvItemToQueue,

                             BaseType_t *pxHigherPriorityTaskWoken);

其中,pxHigherPriorityTaskWoken是输出参数,若因发送唤醒了更高优先级任务则置为pdTRUE,当pxHigherPriorityTaskWoken = pdTRUE时,使用后必须调用portYIELD_FROM_ISR()函数触发上下文切换,否则出了中断程序后会出现任务调度异常。

3、队列的创建和常见配置

队列的配置原则如下表所示:

参数 优化建议
​****深度(Length) 避免过深(浪费内存),过浅(频繁阻塞)
​****项目大小(Item Size) 大于20字节时建议传递指针(启用configSUPPORT_DYNAMIC_ALLOCATION)
​****阻塞时间 生产者和消费者使用不同的超时策略,根据实际应用场景设置

队列的选型指南如下表所示 :

通信需求 推荐组件 特点比较
数据传输(带内容) 标准队列 支持任意数据结构
轻量级通知 队列(零字节项目) 比二进制信号量更节省内存
高频小数据 流缓冲(Stream Buffer) 无项目边界,更高吞吐
结构化流 消息缓冲(Message Buffer) 带长度标识,支持变长数据
广播通信 任务通知(Task Notificaiton) 点对点,零拷贝,最高效

由于队列常用在任务之间的通信,因此系统要配置两个任务来进行队列通信演示:

4、在任务中使用队列

本例程的两个任务中,一个任务负责记录数据,模拟传感器数据写入,另一个任务读出数据,模拟数据处理,通过Keil仿真中的变量内存查看窗口或者硬件LED灯闪烁状态可观察到代码实现的功能现象。

cpp 复制代码
/* 创建队列 */
osMessageQStaticDef(myQueue01, 16, uint16_t, myQueue01Buffer, &myQueue01ControlBlock);
myQueue01Handle = osMessageCreate(osMessageQ(myQueue01), NULL);


/* 创建任务2 */
osThreadStaticDef(myTask02, StartTask02, osPriorityBelowNormal, 0, 128, myTask02Buffer, &myTask02ControlBlock);
myTask02Handle = osThreadCreate(osThread(myTask02), NULL);


/* 创建任务3 */
osThreadStaticDef(myTask03, StartTask03, osPriorityNormal, 0, 128, myTask03Buffer, &myTask03ControlBlock);
myTask03Handle = osThreadCreate(osThread(myTask03), NULL);


/* 任务2的API接口,在里面实现具体功能 */
void StartTask02(void const * argument)
{
  /* USER CODE BEGIN StartTask02 */
    for( ; ; )
    {
        static uint32_t u32Rec = 0;    //创建队列接收缓存

        //队列接收数据,如果队列空,会进入阻塞状态等待队列中数据就绪,直到超时
        if( xQueueReceive(myQueue01Handle, &u32Rec, pdMS_TO_TICKS(50)) != pdTRUE ) 
        {
            //接收失败处理
        }
        else    //如果队列数据接收成功
        {
            if(u32Rec % 2 == 0)    //根据接收到的数据进行分类处理
                LED0_ON;
            else
                LED0_OFF;
        }
        osDelay(200);   //延时,任务进入阻塞态
  }
  /* USER CODE END StartTask02 */
}


/* 任务3的API接口,在里面实现具体功能 */
void StartTask03(void const * argument)
{
  /* USER CODE BEGIN StartTask03 */
    for( ; ; )
    {
        static uint32_t u32Numbers = 0;    //创建数据发送变量,模拟传感器数据

        //队列发送数据,如果队列满,会进入阻塞状态等队列中出现数据空位,如果等待超时,数据丢弃
        if( xQueueSend(myQueue01Handle, &u32Numbers, pdMS_TO_TICKS(100)) != pdTRUE)    
        {
            //发送数据失败处理
        }
        else
        {
            //数据发送成功处理
        }
        u32Numbers++;    //模拟传感器数据变化
        osDelay(50);     //延时,任务进入阻塞态
}
  /* USER CODE END StartTask03 */
}

5、如果这篇文章能帮助到你,请点个赞鼓励一下吧ξ( ✿>◡❛)~

相关推荐
良许Linux2 分钟前
32岁入行STM32迟吗?
stm32·单片机·嵌入式硬件
hjs_deeplearning2 分钟前
认知篇#10:何为分布式与多智能体?二者联系?
人工智能·分布式·深度学习·学习·agent·智能体
m0_4666077031 分钟前
【STM32CubeMX】ST官网MCU固件库下载及安装
stm32·单片机·嵌入式硬件
Wallace Zhang4 小时前
STM32F103_Bootloader程序开发11 - 实现 App 安全跳转至 Bootloader
stm32·嵌入式硬件·安全
GodKK老神灭4 小时前
STM32 CCR寄存器
stm32·单片机·嵌入式硬件
静心问道7 小时前
XLSR-Wav2Vec2:用于语音识别的无监督跨语言表示学习
人工智能·学习·语音识别
杰克逊的日记9 天前
MCU编程
单片机·嵌入式硬件
Python小老六9 天前
单片机测ntc热敏电阻的几种方法(软件)
数据库·单片机·嵌入式硬件
懒惰的bit9 天前
STM32F103C8T6 学习笔记摘要(四)
笔记·stm32·学习
Jay_51510 天前
C++ STL 模板详解:由浅入深掌握标准模板库
c++·学习·stl