STM32 HAL库 Freertos队列使用解析
在基于 STM32F407 HAL 库和 FreeRTOS 的开发中,队列是一种重要的任务间通信机制,它允许任务之间安全地传递数据。下面将详细解析如何使用 FreeRTOS 的队列。
1. 队列的基本概念
队列是一种先进先出(FIFO)的数据结构,在 FreeRTOS 中,队列可以用来在任务之间传递数据。队列中的每个数据项都有固定的大小,并且可以存储多个数据项。
2. 配置开发环境
首先,你需要使用 STM32CubeMX 配置好 STM32F407 的项目,并启用 FreeRTOS。步骤如下:
- 打开 STM32CubeMX,选择 STM32F407 芯片。
- 配置时钟、调试接口等基本设置。
- 在 “Middleware” -> “RTOS” 中选择 FreeRTOS,并进行必要的配置。
- 生成代码并导入到 Keil MDK 中。
3. 队列的创建与使用示例
以下是一个基于 STM32F407 HAL 库和 FreeRTOS 的队列使用示例代码:
stm32f407-freertos-queue基于STM32F407 HAL库和FreeRTOS的队列使用示例代码
生成 main.c
#include "main.h"
#include "stm32f4xx_hal.h"
#include "cmsis_os.h"// 队列句柄
osMessageQId myQueueHandle;// 发送任务函数
void SenderTask(void const * argument)
{uint32_t data = 0;for(;;){// 发送数据到队列if(osMessagePut(myQueueHandle, data, osWaitForever) == osOK){HAL_UART_Transmit(&huart1, (uint8_t *)"Data sent to queue!\r\n", 20, 100);data++;}osDelay(1000); // 每隔1秒发送一次数据}
}// 接收任务函数
void ReceiverTask(void const * argument)
{osEvent event;for(;;){// 从队列中接收数据event = osMessageGet(myQueueHandle, osWaitForever);if(event.status == osEventMessage){uint32_t receivedData = event.value.v;char buffer[50];sprintf(buffer, "Received data: %lu\r\n", receivedData);HAL_UART_Transmit(&huart1, (uint8_t *)buffer, strlen(buffer), 100);}}
}void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_FREERTOS_Init(void);int main(void)
{HAL_Init();SystemClock_Config();MX_GPIO_Init();MX_USART1_UART_Init();MX_FREERTOS_Init();/* 启动调度器 */osKernelStart();while (1){// 主循环一般为空}
}void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** 初始化RCC振荡器 */RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLM = 8;RCC_OscInitStruct.PLL.PLLN = 336;RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;RCC_OscInitStruct.PLL.PLLQ = 7;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** 初始化RCC时钟 */RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK){Error_Handler();}
}static void MX_GPIO_Init(void)
{GPIO_InitTypeDef GPIO_InitStruct = {0};/* GPIO Ports Clock Enable */__HAL_RCC_GPIOA_CLK_ENABLE();/*Configure GPIO pin Output Level */HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);/*Configure GPIO pin : PA5 */GPIO_InitStruct.Pin = GPIO_PIN_5;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;GPIO_InitStruct.Pull = GPIO_NOPULL;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}static void MX_USART1_UART_Init(void)
{huart1.Instance = USART1;huart1.Init.BaudRate = 115200;huart1.Init.WordLength = UART_WORDLENGTH_8B;huart1.Init.StopBits = UART_STOPBITS_1;huart1.Init.Parity = UART_PARITY_NONE;huart1.Init.Mode = UART_MODE_TX_RX;huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart1.Init.OverSampling = UART_OVERSAMPLING_16;if (HAL_UART_Init(&huart1) != HAL_OK){Error_Handler();}
}static void MX_FREERTOS_Init(void)
{// 创建队列osMessageQDef(myQueue, 16, uint32_t);myQueueHandle = osMessageCreate(osMessageQ(myQueue), NULL);// 创建发送任务osThreadDef(SenderTask, SenderTask, osPriorityNormal, 0, 128);osThreadCreate(osThread(SenderTask), NULL);// 创建接收任务osThreadDef(ReceiverTask, ReceiverTask, osPriorityNormal, 0, 128);osThreadCreate(osThread(ReceiverTask), NULL);
}void Error_Handler(void)
{while(1){}
}
4. 代码解析
4.1 队列的创建
在MX_FREERTOS_Init
函数中,使用osMessageQDef
宏定义队列的参数,包括队列名称、队列长度和数据项类型。然后使用osMessageCreate
函数创建队列,并返回队列句柄。
osMessageQDef(myQueue, 16, uint32_t);
myQueueHandle = osMessageCreate(osMessageQ(myQueue), NULL);
这里创建了一个长度为 16,数据项类型为uint32_t
的队列。
4.2 发送数据到队列
在SenderTask
函数中,使用osMessagePut
函数将数据发送到队列中。osWaitForever
表示如果队列已满,任务将一直等待直到有空间可用。
if(osMessagePut(myQueueHandle, data, osWaitForever) == osOK)
{HAL_UART_Transmit(&huart1, (uint8_t *)"Data sent to queue!\r\n", 20, 100);data++;
}
4.3 从队列中接收数据
在ReceiverTask
函数中,使用osMessageGet
函数从队列中接收数据。osWaitForever
表示如果队列为空,任务将一直等待直到有数据可用。
event = osMessageGet(myQueueHandle, osWaitForever);
if(event.status == osEventMessage)
{uint32_t receivedData = event.value.v;char buffer[50];sprintf(buffer, "Received data: %lu\r\n", receivedData);HAL_UART_Transmit(&huart1, (uint8_t *)buffer, strlen(buffer), 100);
}
5. 注意事项
- 队列长度:队列的长度决定了队列可以存储的数据项数量。如果队列已满,继续发送数据可能会导致任务阻塞。
- 数据类型:队列中的数据项必须是相同的数据类型,在创建队列时需要明确指定。
- 错误处理:在使用
osMessagePut
和osMessageGet
函数时,需要检查返回值以确保操作成功。
通过以上步骤,你可以在基于 STM32F407 HAL 库和 FreeRTOS 的项目中使用队列进行任务间通信。