【STM32L4】FreeRTOS消息队列三串口接收发送

环境

  • STM32L476G-DISCO 开发板
  • STM32CubeIDE 1.1.0
  • STM32CubeMX 5.4.0

STM32CubeIDE配置

移植FreeRTOS,选择CMSIS_V2。
【STM32L4】FreeRTOS消息队列三串口接收发送_第1张图片
FreeRTOS的所有配置的选择默认,后面手动修改FreeRTOSConfig.h文件修改配置。如果想直接在IDE中修改配置也可以直接修改。

开启三个串口,异步模式。
【STM32L4】FreeRTOS消息队列三串口接收发送_第2张图片
由于接收采用空闲中断接收,所以要打开DMA接收和串口总中断。

重要文件

  • FreeRTOSConfigure.h FreeRTOS的配置文件。修改一些关于FreeRTOS的配置信息。
  • freertos.c FreeRTOS任务主文件,可以在void MX_FREERTOS_Init(void)函数中定义任务。

默认STM32CubeIDE在生成代码的时候是会在MA_FREERTOS_Init函数创建一个默认任务。该任务的功能仅仅做一个延时。

代码

FreeRTOSConfigure.h

#define configTOTAL_HEAP_SIZE       ((size_t)1024 * 24)
//修改Total Heap Size,该参数决定内存池的总大小,当FreeRTOS任务启动后总是进入HardFault_Handler中断程序时,可以考虑Debug看一下任务句柄地址的分配,很可能是因为内存池资源用完,没有空间分配导致的硬件异常中断。

main.h

/* USER CODE BEGIN Private defines */
#define UARTRXBUFFERSIZE 512     //串口接收的缓存区大小
#define UARTQUEUENUM  3          //消息队列的数量
#define UARTQUEUESIZE (uint32_t)UARTRXBUFFERSIZE * UARTQUEUENUM

typedef struct {
	uint8_t uartRxTemp[UARTRXBUFFERSIZE];
	uint8_t uartRxName[7];
} UARTMessageQueue_TypeDef;
/* USER CODE END Private defines */
//自己定义了一些宏和结构体

stm32l4xx_it.c

/* USER CODE BEGIN EV */
//在main.c文件中定义的串口接收缓存区,大小为UARTRXBUFFERSIZE
extern uint8_t uart1RxBuffer[UARTRXBUFFERSIZE];
extern uint8_t uart2RxBuffer[UARTRXBUFFERSIZE];
extern uint8_t uart4RxBuffer[UARTRXBUFFERSIZE];

//在freertos.c文件中定义的消息队列句柄
extern osMessageQueueId_t osQueueUart1;
extern osMessageQueueId_t osQueueUart2;
extern osMessageQueueId_t osQueueUart4;
/* USER CODE END EV */

/**
 * @brief This function handles USART1 global interrupt.
 */
void USART1_IRQHandler(void) {
	/* USER CODE BEGIN USART1_IRQn 0 */
	uint8_t temp;
	UARTMessageQueue_TypeDef msg;
	uint8_t str[7] = "USART1";
	if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET) {
		//空闲中断
		//temp = huart4.Instance->ISR;
		__HAL_UART_CLEAR_IDLEFLAG(&huart1);
		temp = huart1.Instance->RDR;
		temp = temp;
		HAL_UART_DMAStop(&huart1);
        //进入串口空闲中断之后,确定串口数据缓存区有数据,将串口数据存入结构体的数据存储数组,结构体的uartRxName成员存放消息来源的串口名称。
        //osMessageQueuePut将结构体推入osQueueUart1消息队列中。
        //其实可以将三个串口放入一个消息队列,用结构体中uartRxName成员区分来源。这里为了简单明了,没有做更多的优化。有兴趣可以自行修改。
		if (strlen(uart1RxBuffer) != 0) {
			memset(msg.uartRxTemp, 0x00, sizeof(msg.uartRxTemp));
			memcpy(msg.uartRxTemp, uart1RxBuffer, strlen(uart1RxBuffer));
			memcpy(msg.uartRxName, str, strlen(str));
			memset(uart1RxBuffer, 0x00, strlen(uart1RxBuffer));
			osMessageQueuePut(osQueueUart1, &msg, 0, 0);
		}

		__HAL_UART_CLEAR_IDLEFLAG(&huart1);
		__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
		HAL_UART_Receive_DMA(&huart1, uart1RxBuffer, UARTRXBUFFERSIZE);
	}
	/* USER CODE END USART1_IRQn 0 */
	HAL_UART_IRQHandler(&huart1);
	/* USER CODE BEGIN USART1_IRQn 1 */

	/* USER CODE END USART1_IRQn 1 */
}

/**
 * @brief This function handles USART2 global interrupt.
 */
void USART2_IRQHandler(void) {
	/* USER CODE BEGIN USART2_IRQn 0 */
	uint8_t temp;
	UARTMessageQueue_TypeDef msg;
	uint8_t str[7] = "USART2";
	if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE) != RESET) {
		//空闲中断
		//temp = huart4.Instance->ISR;
		__HAL_UART_CLEAR_IDLEFLAG(&huart2);
		temp = huart2.Instance->RDR;
		temp = temp;
		HAL_UART_DMAStop(&huart2);

		if (strlen(uart2RxBuffer) != 0) {
			memset(msg.uartRxTemp, 0x00, sizeof(msg.uartRxTemp));
			memcpy(msg.uartRxTemp, uart2RxBuffer, strlen(uart2RxBuffer));
			memcpy(msg.uartRxName, str, strlen(str));
			memset(uart2RxBuffer, 0x00, strlen(uart2RxBuffer));
			osMessageQueuePut(osQueueUart2, &msg, 0, 0);
		}

		__HAL_UART_CLEAR_IDLEFLAG(&huart2);
		__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
		HAL_UART_Receive_DMA(&huart2, uart2RxBuffer, UARTRXBUFFERSIZE);
	}
	/* USER CODE END USART2_IRQn 0 */
	HAL_UART_IRQHandler(&huart2);
	/* USER CODE BEGIN USART2_IRQn 1 */

	/* USER CODE END USART2_IRQn 1 */
}

/**
 * @brief This function handles UART4 global interrupt.
 */
void UART4_IRQHandler(void) {
	/* USER CODE BEGIN UART4_IRQn 0 */
	uint8_t temp;
	UARTMessageQueue_TypeDef msg;
	uint8_t str[7] = "UART4";
	if (__HAL_UART_GET_FLAG(&huart4, UART_FLAG_IDLE) != RESET) {
		//空闲中断
		//temp = huart4.Instance->ISR;
		__HAL_UART_CLEAR_IDLEFLAG(&huart4);
		temp = huart4.Instance->RDR;
		temp = temp;
		HAL_UART_DMAStop(&huart4);

		if (strlen(uart4RxBuffer) != 0) {
			memset(msg.uartRxTemp, 0x00, sizeof(msg.uartRxTemp));
			memcpy(msg.uartRxTemp, uart4RxBuffer, strlen(uart4RxBuffer));
			memcpy(msg.uartRxName, str, strlen(str));
			memset(uart4RxBuffer, 0x00, strlen(uart4RxBuffer));
			osMessageQueuePut(osQueueUart4, &msg, 0, 0);
		}

		__HAL_UART_CLEAR_IDLEFLAG(&huart4);
		__HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);
		HAL_UART_Receive_DMA(&huart4, uart4RxBuffer, UARTRXBUFFERSIZE);
	}
	/* USER CODE END UART4_IRQn 0 */
	HAL_UART_IRQHandler(&huart4);
	/* USER CODE BEGIN UART4_IRQn 1 */

	/* USER CODE END UART4_IRQn 1 */
}

main.c

/* USER CODE BEGIN PV */
uint8_t uart1RxBuffer[UARTRXBUFFERSIZE] = { 0 };
uint8_t uart2RxBuffer[UARTRXBUFFERSIZE] = { 0 };
uint8_t uart4RxBuffer[UARTRXBUFFERSIZE] = { 0 };

/* USER CODE END PV */
//定义串口数据的缓存区,DMA将串口接收的数据搬运到这个缓存区中。

/* USER CODE BEGIN 4 */
/* 开启IDLE空闲中断、错误中断和DMA接收。
 *
 */
void uartEnableIDLE(void) {
	__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
	__HAL_UART_ENABLE_IT(&huart1, UART_IT_ERR);
	HAL_UART_Receive_DMA(&huart1, uart1RxBuffer, UARTRXBUFFERSIZE);
	__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
	__HAL_UART_ENABLE_IT(&huart2, UART_IT_ERR);
	HAL_UART_Receive_DMA(&huart2, uart2RxBuffer, UARTRXBUFFERSIZE);
	__HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);
	__HAL_UART_ENABLE_IT(&huart4, UART_IT_ERR);
	HAL_UART_Receive_DMA(&huart4, uart4RxBuffer, UARTRXBUFFERSIZE);
}

/**
 * @brief  UART error callback.
 * @param  huart UART handle.
 * @retval None
 */
 //错误接收中断回调函数,用于处理ORE溢出中断。其他错误中断也可以在这个函数中处理。
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {
	/* Prevent unused argument(s) compilation warning */
	UNUSED(huart);
	uint8_t temp;
	/* NOTE : This function should not be modified, when the callback is needed,
	 the HAL_UART_ErrorCallback can be implemented in the user file.
	 */
	if (huart->Instance == USART1) {
		if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_ORE) != RESET) {
			temp = huart1.Instance->RDR;
			temp = temp;
			__HAL_UART_CLEAR_OREFLAG(&huart1);
			HAL_UART_Receive_DMA(&huart1, uart1RxBuffer, UARTRXBUFFERSIZE);
		}
	} else if (huart->Instance == USART2) {
		if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_ORE) != RESET) {
			temp = huart2.Instance->RDR;
			temp = temp;
			__HAL_UART_CLEAR_OREFLAG(&huart2);
			HAL_UART_Receive_DMA(&huart2, uart2RxBuffer, UARTRXBUFFERSIZE);
		}
	} else if (huart->Instance == UART4) {
		if (__HAL_UART_GET_FLAG(&huart4, UART_FLAG_ORE) != RESET) {
			temp = huart4.Instance->RDR;
			temp = temp;
			__HAL_UART_CLEAR_OREFLAG(&huart4);
			HAL_UART_Receive_DMA(&huart4, uart4RxBuffer, UARTRXBUFFERSIZE);
		}
	}
}
/* USER CODE END 4 */

freertos.c

/* USER CODE BEGIN Variables */
osMessageQueueId_t osQueueUart1;
osMessageQueueId_t osQueueUart2;
osMessageQueueId_t osQueueUart4;

osThreadId_t uart1TaskHandle;
osThreadId_t uart2TaskHandle;
osThreadId_t uart4TaskHandle;
/* USER CODE END Variables */
//定义三个消息队列句柄,三个任务句柄

/* USER CODE BEGIN FunctionPrototypes */
void uart1RxTask(void *argument);
void uart2RxTask(void *argument);
void uart4RxTask(void *argument);
/* USER CODE END FunctionPrototypes */
//声明任务函数

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

	/* USER CODE END Init */
	osKernelInitialize();

	/* 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, ... */
    //新建队列
    //osMessageQueueNew参数分别为队列中消息数量,消息的大小,队列的参数配置 
	osQueueUart1 = osMessageQueueNew(UARTQUEUENUM, sizeof(UARTMessageQueue_TypeDef), NULL);
	osQueueUart2 = osMessageQueueNew(UARTQUEUENUM, sizeof(UARTMessageQueue_TypeDef), NULL);
	osQueueUart4 = osMessageQueueNew(UARTQUEUENUM, sizeof(UARTMessageQueue_TypeDef), NULL);
	/* USER CODE END RTOS_QUEUES */

	/* Create the thread(s) */
	/* definition and creation of defaultTask */
	//const osThreadAttr_t defaultTask_attributes = { .name = "defaultTask",
	//		.priority = (osPriority_t) osPriorityNormal, .stack_size = 128 };
	//defaultTaskHandle = osThreadNew(StartDefaultTask, NULL,
	//		&defaultTask_attributes);

    //osThreadAttr_t 任务线程的结构体
    //.name 任务的名字
    //.priority 任务的优先级
    //.stack_size 任务堆栈的大小

	const osThreadAttr_t uart1RxTask_attributes = { .name = "uart1RxTask",
			.priority = (osPriority_t) osPriorityNormal, .stack_size = 1024 };
    //osThreadNew 创建任务函数,参数分别为任务处理函数,需要传入任务的参数,任务的参数属性
	uart1TaskHandle = osThreadNew(uart1RxTask, NULL, &uart1RxTask_attributes);
	const osThreadAttr_t uart2RxTask_attributes = { .name = "uart2RxTask",
			.priority = (osPriority_t) osPriorityNormal, .stack_size = 1024 };
	uart2TaskHandle = osThreadNew(uart2RxTask, NULL, &uart2RxTask_attributes);
	const osThreadAttr_t uart4RxTask_attributes = { .name = "uart4RxTask",
			.priority = (osPriority_t) osPriorityNormal, .stack_size = 1024 };
	uart4TaskHandle = osThreadNew(uart4RxTask, NULL, &uart4RxTask_attributes);
	/* USER CODE BEGIN RTOS_THREADS */
	/* add threads, ... */
	/* USER CODE END RTOS_THREADS */

}

/* USER CODE BEGIN Application */
void uart1RxTask(void *argument) {
	UARTMessageQueue_TypeDef msg;
	osStatus_t status;
	while (1) {
        //不断的请求消息队列
		status = osMessageQueueGet(osQueueUart1, &msg, NULL, 0);
        //请求到消息队列,将消息中的数据转发出去。
		if (status == osOK) {
			HAL_UART_Transmit(&huart1, msg.uartRxTemp, strlen(msg.uartRxTemp),
					1000);
			memset(msg.uartRxTemp, 0x00, strlen(msg.uartRxTemp));
		}
		osThreadYield();
	}
}

void uart2RxTask(void *argument) {
	UARTMessageQueue_TypeDef msg;
	osStatus_t status;
	while (1) {
		status = osMessageQueueGet(osQueueUart2, &msg, NULL, 0);

		if (status == osOK) {
			HAL_UART_Transmit(&huart2, msg.uartRxTemp, strlen(msg.uartRxTemp),
					1000);
			memset(msg.uartRxTemp, 0x00, strlen(msg.uartRxTemp));
		}
		osThreadYield();
	}
}

void uart4RxTask(void *argument) {
	UARTMessageQueue_TypeDef msg;
	osStatus_t status;
	while (1) {
		status = osMessageQueueGet(osQueueUart4, &msg, NULL, 0);

		if (status == osOK) {
			HAL_UART_Transmit(&huart4, msg.uartRxTemp, strlen(msg.uartRxTemp),
					1000);
			memset(msg.uartRxTemp, 0x00, strlen(msg.uartRxTemp));
		}
		osThreadYield();
	}
}
/* USER CODE END Application */

工程代码

如果愿意支持一下可以选择在CSDN下载,下载地址:
//download.csdn.net/download/JoelYang1997/12013095
同时如果没有下载币提供GIthub地址:
https://github.com/joelyang97/32L4_FreeRTOSandUART

你可能感兴趣的:(STM32)