引言
在嵌入式开发领域,STM32与FreeRTOS的结合应用极为广泛。本文将探讨如何在STM32上使用FreeRTOS实现消息队列功能,助力高效任务通信与系统协作。
消息队列定义
消息队列是一种在 FreeRTOS 中用于任务间通信的机制。它允许任务将消息发送到队列中,其他任务可以从队列中接收这些消息。消息队列可以存储多种类型的数据,如整数、指针或结构体等。通过消息队列,任务之间可以实现解耦,提高系统的可维护性和可扩展性。在 STM32 系统中,合理使用消息队列可以有效协调多个任务的运行,优化资源分配,确保系统的高效稳定运行。
创建消息队列
跟前面创建任务一样,在起始函数中创建消息队列
void MyTask(void *arg) //开始创建任务函数
{taskENTER_CRITICAL(); //进入临界区 /* 创建Task_Queue */Task_Queue = xQueueCreate(QUEUE_LEN,QUEUE_SIZE);//xQueueCreate(队列消息的长度,队列消息的大小)xTaskCreate(MyTask1,"MyTask1",50,NULL,2,&MyTask1Handler);//动态方法创建任务1xTaskCreate(Receive_task,"Receive_task",50,NULL,3,&ReceiveTask_Handler);//创建接收消息任务xTaskCreate(Send_task,"Send_task",50,NULL,4,&SendTask_Handler); //创建发送消息任务vTaskDelete(MyTaskHandler); //删除开始任务taskEXIT_CRITICAL(); //退出临界区
}
xQueueCreate(*队列长度,*队列消息大小)
xQueueCreate()是FreeRTOS中用于创建消息队列的函数,其函数原型为:
QueueHandle_t xQueueCreate(
UBaseType_t uxQueueLength,
UBaseType_t uxItemSize
);
参数uxQueueLength是队列的长度,即队列可以容纳的最大消息数量。参数uxItemSize表示队列中每个消息的大小,通常以字节为单位。该函数还有一个返回值,如果队列创建成功,则返回队列的句柄;如果失败则返回NULL。
创建发送队列消息任务函数
同样先创建任务函数,然后调用xQueueSend()发送队列消息函数,其函数原型如下:
BaseType_t xQueueSend(
QueueHandle_t xQueue,
const void *pvItemToQueue,
TickType_t xTicksToWait
)
xQueueSend()是FreeRTOS 中用于向消息队列发送消息的函数。它允许任务将数据发送到队列中,供其他任务接收。参数xQueue指向要发送消息的队列的句柄,这个句柄是用户通过xQueueCreate创建时返回的。在上面已经定义成Task_Queue;参数*pvItemToQueue是一个指针类型,指向要发送到队列的数据的值。参数xTicksToWait表示等待时间,这个时间通常是由systick滴答定时器提供,前面的文章已经讲过,这里不再论述。如果队列已满,xTicksToWait()的行为取决于xTicksToWait()的值,如果为0,则函数返回pdFAIL;如果为非0值,任务将阻塞直到队列有空间或等待时间已到,函数才会返回pdFAIL。(pdFAIL表示发送队列消息失败)
创建接收队列消息任务函数
跟前面一样,这里直接跳过。然后调用xQueueReceive()接收队列消息函数。其函数原型为:
BaseType_t xQueueReceive(
QueueHandle_t xQueue, // 队列的句柄
void *pvBuffer, // 用于存储接收到的数据的缓冲区
TickType_t xTicksToWait // 等待队列可用的时间
)
xQueueReceive()是 FreeRTOS 提供的一个函数,用于从队列中接收数据。它通常用于任务之间通过队列进行通信。参数xQueue表示队列的句柄,指向要从中接收数据的队列;参数*pvBuffer指向一个缓冲区,用于存储从队列中接收到的数据,缓冲区的大小尽量与队列中存储的数据大小一致。参数xTicksToWait 跟上面一样。
示例代码
#include "myfreertos.h"
#include "FreeRTOS.h"
#include "semphr.h"
#include "queue.h"
#include "Usart.h"
#include "oled.h"
#include "Task.h"
#include "led.h"
#include "key.h"#define QUEUE_LEN 4 /* 队列的长度,最大可包含多少个消息 */
#define QUEUE_SIZE 4 /* 队列中每个消息大小(字节) */QueueHandle_t Task_Queue =NULL; //消息队列句柄TaskHandle_t MyTaskHandler;//任务句柄TaskHandle_t MyTask1Handler;//任务1句柄TaskHandle_t SendTask_Handler; //发送消息句柄TaskHandle_t ReceiveTask_Handler;//接收消息句柄void MyTask(void *pvParameters); //声明启动函数void MyTask1(void *pvParameters); //声明任务1函数void Send_task(void *pvParameters); //声明发送消息函数void Receive_task(void *pvParameters); //声明接收消息函数void Start_Task(void)
{xTaskCreate(MyTask,"MyTask",128,NULL,1,&MyTaskHandler);//动态方法创建任务vTaskStartScheduler();//启动任务调动
}void MyTask(void *arg) //开始创建任务函数
{taskENTER_CRITICAL(); //进入临界区 /* 创建Task_Queue */Task_Queue = xQueueCreate(QUEUE_LEN,QUEUE_SIZE);//xQueueCreate(队列消息的长度,队列消息的大小)xTaskCreate(MyTask1,"MyTask1",50,NULL,2,&MyTask1Handler);//动态方法创建任务1xTaskCreate(Receive_task,"Receive_task",50,NULL,3,&ReceiveTask_Handler);//创建接收消息任务xTaskCreate(Send_task,"Send_task",50,NULL,4,&SendTask_Handler); //创建发送消息任务vTaskDelete(MyTaskHandler); //删除开始任务taskEXIT_CRITICAL(); //退出临界区
}void MyTask1(void *arg) //任务1函数体
{
// u32 cnt=0; //定义变量while(1){OLED_ShowString(1,1,"Runing Task1");GPIO_ResetBits(GPIOC,GPIO_Pin_13);vTaskDelay(300);GPIO_SetBits(GPIOC,GPIO_Pin_13);vTaskDelay(900);
// if(++cnt>=10) //如果超过10次
// {
// if(MyTask1Handler!=NULL) //判断句柄是否有效
// {
// vTaskDelete(MyTask1Handler); //删除任务1
// MyTask1Handler=NULL; //清空句柄
// }
// }}
}//接收队列消息任务函数
void Receive_task(void *pvParameters)
{BaseType_t xReturn = pdTRUE;/* 定义一个创建信息返回值,默认为pdTRUE */uint32_t r_queue; /* 定义一个接收消息的变量 */while(1){xReturn = xQueueReceive(Task_Queue,&r_queue,portMAX_DELAY); //xQueueReceive(队列消息句柄,接收队列消息的内容,等待时间)if(pdTRUE == xReturn) //判断是否接收到消息OLED_ShowNum(2,1,r_queue,1); //显示接收的消息}
}//发送队列消息任务函数
void Send_task(void *pvParameters)
{BaseType_t xReturn = pdPASS;/* 定义一个创建信息返回值,默认为pdPASS */uint32_t send_data1 = 1; //定义发送的数据uint32_t send_data2 = 2; //定义发送的数据while(1){if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6)==1){xReturn = xQueueSend(Task_Queue,&send_data1,10);//向队列发送数据 if(pdPASS == xReturn) //判断是否发送成功{OLED_ShowString(3,1,"Send_OK ");}}else{ xReturn = xQueueSend( Task_Queue,&send_data2,10); OLED_ShowString(3,1,"Send_OFF");}vTaskDelay(20);}
}
总结
本文介绍了 STM32 中 FreeRTOS 操作系统的消息队列功能,包括其创建、发送、接收等操作方法,以及在嵌入式开发中的应用实例,有助于提高多任务通信效率(如有不足,欢迎指出)。