小工具知识网

当前位置: 首页 > 行业知识 > FreeRTOS【7】队列使用

行业知识

FreeRTOS【7】队列使用

2026-11-12 12:59:43 来源:互联网转载

1.开发背景

       操作系统提供了多线程并行的操作,为了方便代码的维护,各个线程都分配了专用的内存并处理对应的内容。但是线程间也是需要协助操作的,例如一个主线程接收信息,会把接收的信息并发到其他线程,即主线程不阻塞,子线程做实际的处理。

        如果是在裸机编程的方式,常用的操作方式是主线程设置 Flag,子线程循环查询 Flag 是否达到预期再执行对应的操作。问题就来了,为了提高子线程的响应实时性,需要频繁判断,导致CPU占用率极高,显然这样的设计是不合理的,所以队列的存在就变得合理了。

        FreeRTOS 的队列传递信息采用的是内存拷贝,队列在接收信息的时候会阻塞线程,释放CPU,降低 CPU 的使用率,相当于线程间信息的交互交给内核去统筹。

        下面是队列的常用接口,不包含中断操作,需要注意的是 xQueueOverwrite只在单成员队列中使用。

        鉴于有些人是不知道队列的特性的,队列就是先进先出,当然 FreeRTOS 提供了队头插队的操作,总体如下图:

2.开发需求

        设计实验实现线程到线程,中断到线程的信息传递。

3.开发环境

        window10 + MDK + STM32F429 + FreeRTOS10.3.1

4.实现步骤

1)创建接收线程,持续等待队列信息

2)创建发送线程,发送队列信息

3)重写按键中断,中断中发送队列信息

        核心代码如下:

#include "appTest.h"#include #include #include #include "mspDwt.h"#include "mspGpio.h"#include "mspExti.h"#include "FreeRTOS.h"#include "task.h"#include "queue.h"#include "appLog.h"typedef struct{    /* 队列相关 */    QueueHandle_t queue;            // 队列句柄        /* 创建任务 */    TaskHandle_t taskCtrl;          // 控制线程    TaskHandle_t taskQueueRx;       // 接收线程    TaskHandle_t taskQueueTx;       // 发送线程    }Ctrl_t;/* 文件指针 */static Ctrl_t s_ctrl = {0};static Ctrl_t *p = &s_ctrl;static void TaskCtrl(void *pvParameters);static void TaskQueueRx(void *pvParameters);static void TaskQueueTx(void *pvParameters);/* 控制线程 */static void TaskCtrl(void *pvParameters){    vTaskDelay(1000);    for ( ; ; )    {        vTaskDelay(1000);    }}/* 队列接收线程 */static void TaskQueueRx(void *pvParameters){    unsigned int item = 0;    vTaskDelay(100);        for ( ; ; )    {        xQueueReceive(p->queue, &item, portMAX_DELAY);        Log_Debug("%s 线程接收 Rx = 0x%.8X\r\n", __func__, item);    }}/* 队列发送线程 */static void TaskQueueTx(void *pvParameters){    vTaskDelay(1000);        unsigned int threadData = 0x12345678;    xQueueSend(p->queue, &threadData, 1000);    Log_Debug("%s 线程发送 Tx = 0x%.8X\r\n", __func__, threadData);        for ( ; ; )    {        vTaskDelay(1000);    }}/* 测试初始化 */void aTest_Init(void){    /* 创建队列 */    UBaseType_t uxQueueLength = 10;    UBaseType_t uxItemSize = sizeof(unsigned int);    p->queue = xQueueCreate(uxQueueLength, uxItemSize);        /* 创建动态任务 */    xTaskCreate(TaskCtrl,       "TaskCtrl",     500, NULL, 5, &p->taskCtrl);    xTaskCreate(TaskQueueRx,    "TaskQueueRx",  500, NULL, 5, &p->taskQueueRx);    xTaskCreate(TaskQueueTx,    "TaskQueueTx",  500, NULL, 5, &p->taskQueueTx);}/* Key2 PC13   Key0 PH3 Key1 PH2 */void Exti13_TriggerInterrupt(void){    mspExti_Close(13);        if (mspGpio_GetInput("PC13") == 0)    {        /* 队列发送数据 */        unsigned int irqData = 0xABCDEF;        BaseType_t xHigherPriorityTaskWoken;        xQueueSendFromISR(p->queue, &irqData, &xHigherPriorityTaskWoken);        portYIELD_FROM_ISR(xHigherPriorityTaskWoken);        Log_Debug("%s 中断发送 Tx = 0x%.8X\r\n", __func__, irqData);    }}

4)查看运行结果

        线程和中断发送的数据都被接收无误,而且通过时间戳可以看出,线程发送完 1ms 内数据就被接收线程接收并处理,实时性还是很不错的。

上一篇:uniapp+node.js前后端做帖子模块:查看帖子(获取帖子详情以及对应的帖子评论列表)(社区管理平台的小程序)

下一篇:服务器怎么评价?