【STM32】基于STM32CubeMX的凭借Queue队列管理的串口空闲中断接收数据(有操作系统)

一、框架概述

  该方案采用的是基于FreeRTOS下的凭借Queue队列管理的串口空闲中断来接收数据。

 二、STM32CubeMX的配置

1、时钟配置

2、时钟源换为TIM6(systick需要提供给FreeRTOS)

3、串口配置(这里未开启DMA)

 

4、FreeRTOS的配置(开启后就直接按默认配置,若有自身需求,请自行进行其他的配置)

5、时钟树的配置

6、工程的配置

  至此,STM32CubeMX配置完毕。

三、代码编写

freertos.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : freertos.c
  * Description        : Code for freertos applications
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2025 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "BSP_USART.h"
#include "queue.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */

/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
//定义串口测试任务句柄
static TaskHandle_t sg_xUART_TestOfTaskHandle;

//定义接收队列句柄
QueueHandle_t g_xQueueHandle_UART_RX;

/* USER CODE END Variables */
osThreadId defaultTaskHandle;

/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes */

/* USER CODE END FunctionPrototypes */

void StartDefaultTask(void const * argument);

void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */

/* GetIdleTaskMemory prototype (linked to static allocation support) */
void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize );

/* USER CODE BEGIN GET_IDLE_TASK_MEMORY */
static StaticTask_t xIdleTaskTCBBuffer;
static StackType_t xIdleStack[configMINIMAL_STACK_SIZE];

void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackType_t **ppxIdleTaskStackBuffer, uint32_t *pulIdleTaskStackSize )
{
  *ppxIdleTaskTCBBuffer = &xIdleTaskTCBBuffer;
  *ppxIdleTaskStackBuffer = &xIdleStack[0];
  *pulIdleTaskStackSize = configMINIMAL_STACK_SIZE;
  /* place for user code */
}
/* USER CODE END GET_IDLE_TASK_MEMORY */

/**
  * @brief  FreeRTOS initialization
  * @param  None
  * @retval None
  */
void MX_FREERTOS_Init(void) {
  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* USER CODE BEGIN RTOS_MUTEX */
  /* add mutexes, ... */
  /* USER CODE END RTOS_MUTEX */

  /* USER CODE BEGIN RTOS_SEMAPHORES */
  /* add semaphores, ... */
	
  /* USER CODE END RTOS_SEMAPHORES */

  /* USER CODE BEGIN RTOS_TIMERS */
  /* start timers, add new ones, ... */
  /* USER CODE END RTOS_TIMERS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
	//动态创建接收队列
	g_xQueueHandle_UART_RX = xQueueCreate(3, sizeof(uint8_t));
  /* USER CODE END RTOS_QUEUES */

  /* Create the thread(s) */
  /* definition and creation of defaultTask */
  osThreadDef(defaultTask, StartDefaultTask, osPriorityNormal, 0, 256);
  defaultTaskHandle = osThreadCreate(osThread(defaultTask), NULL);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  //动态创建串口测试任务
	xTaskCreate(UART_Test, "UART_Test_TASK", 128, NULL, osPriorityNormal+1, &sg_xUART_TestOfTaskHandle);
	
  /* USER CODE END RTOS_THREADS */

}

/* USER CODE BEGIN Header_StartDefaultTask */
/**
  * @brief  Function implementing the defaultTask thread.
  * @param  argument: Not used
  * @retval None
  */
/* USER CODE END Header_StartDefaultTask */
void StartDefaultTask(void const * argument)
{
  /* USER CODE BEGIN StartDefaultTask */
  /* Infinite loop */
  for(;;)
  {
    osDelay(1);
  }
  /* USER CODE END StartDefaultTask */
}

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */

/* USER CODE END Application */

BSP_USART.h

#ifndef __BSP_USART_H
#define __BSP_USART_H

#include "stm32f1xx_hal.h"

#define Buffer_Total_Length 10

void UART_Test(void *pvParamter);
void UsartPrintf(UART_HandleTypeDef *USARTx, char *fmt,...);
#endif

BSP_USART.c

#include "BSP_USART.h"
//STM32
#include "usart.h"
//FreeRTOS
#include "freertos.h"
#include "queue.h"
#include "semphr.h"
//C
#include "stdio.h"
#include <stdarg.h>
#include <string.h>

//外部声明
extern QueueHandle_t g_xQueueHandle_UART_RX;

//接受数组
uint8_t RX_Buffer[Buffer_Total_Length] = {0};
//用户测试数组
uint8_t USER_RX_Buffer[Buffer_Total_Length] = {0};

//初始化
void UART_Init(void )
{	
	__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
	HAL_UART_Receive_IT(&huart1, RX_Buffer, sizeof(RX_Buffer));
}

//测试任务
void UART_Test(void *pvParamter)
{
	UART_Init();
	
	while(1)
	{
		
		if(xQueueReceive(g_xQueueHandle_UART_RX, USER_RX_Buffer, portMAX_DELAY) == pdTRUE)
		{
			//打印并回显接收的数据的第一个字符
			UsartPrintf(&huart1, "%d", USER_RX_Buffer[0]);
		}
			
	}
}


//自定义打印函数
void UsartPrintf(UART_HandleTypeDef *USARTx, char *fmt, ...)
{
    unsigned char UsartPrintfBuf[256];
    va_list ap;
    unsigned int len;
    
    va_start(ap, fmt);
    len = vsnprintf((char *)UsartPrintfBuf, sizeof(UsartPrintfBuf), fmt, ap);
    va_end(ap);
    
    if (len > 0) {
        HAL_UART_Transmit(USARTx, UsartPrintfBuf, len, 1000);
        while(HAL_UART_GetState(USARTx) == HAL_UART_STATE_BUSY_TX);
    }
}

// 在BSP_USART.c中添加中断回调实现
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    if (huart == &huart1) {
		
		// 将接收到的数据发送到队列
        if (g_xQueueHandle_UART_RX != NULL) 
		{
            xQueueSendFromISR(g_xQueueHandle_UART_RX, RX_Buffer, NULL);
        }
		
        // 继续监听下一个字节
        HAL_UART_Receive_IT(&huart1, RX_Buffer, sizeof(RX_Buffer));
		
    }
}

四、实验效果

注意事项:

1、使用的硬件平台是野火指南者开发板(STM32F103VET6)。

2、本来的设想是队列加二值信号量来构建一下对于接收数据的管理,但是,在过程中发现如果在这个中断回调里使用释放二值信号量(任务while中等待获取二值信号量),会导致无法进入中断完成回调函数里,目前原因未知,所以放弃使用二值信号量。

3、在这个过程中,注意到了对于void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);这个中断接收完成回调函数,进入这个回调函数之前就对接收缓存非空、空闲中断标志位置1并且清零了,所以不用在这个中断接收完成回调函数里使用if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE/IDLE)==SET){};这个再去判断一次了。

posted @ 2025-05-28 22:12  Molesidy  阅读(76)  评论(0)    收藏  举报  来源
//雪花飘落效果