在STM32 FreeRTOS环境中使用mutex和ringbuffer实现多任务的UART同步通信。完整的STM32 FreeRTOS UART多任务同步方案,主要特点包括:
核心组件
1. 环形缓冲区 (RingBuffer)
- 发送和接收各有独立的环形缓冲区
- 支持多生产者/消费者模式
- 提供满/空状态检查
2. 互斥量 (Mutex)
txMutex
: 保护发送操作的线程安全rxMutex
: 保护接收操作的线程安全- 防止多任务同时访问UART资源
3. 信号量和队列
txSemaphore
: 发送完成通知rxQueue
: 接收数据通知队列
使用方法
初始化:
c
// 在main函数中调用
UartMultiTask_Init(&huart1);
发送数据:
c
char msg[] = "Hello World\r\n";
UartManager_Transmit(&uart1_manager, (uint8_t*)msg, strlen(msg), 1000);
接收数据:
c
uint8_t rxBuffer[64];
uint16_t len = UartManager_Receive(&uart1_manager, rxBuffer, sizeof(rxBuffer), 1000);
同步机制
- 发送同步: 使用互斥量确保同一时间只有一个任务可以发送
- 接收同步: 通过队列通知机制实现异步接收
- 中断安全 : 在中断中使用
FromISR
版本的FreeRTOS API
任务示例
代码中包含三个示例任务:
- UartSendTask: 定期发送消息
- UartReceiveTask: 接收数据并回显
- UartLogTask: 系统日志输出
这个方案确保了多任务环境下UART通信的稳定性和线程安全性,适用于需要多个任务同时使用UART的复杂应用场景。
实现代码如下:
bash
/* STM32 FreeRTOS UART多任务同步实现 */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "queue.h"
#include "stm32f4xx_hal.h"
#include <string.h>
#include <stdio.h>
/* 环形缓冲区结构 */
typedef struct {
uint8_t *buffer;
uint16_t head;
uint16_t tail;
uint16_t size;
uint16_t count;
} RingBuffer_t;
/* UART管理结构 */
typedef struct {
UART_HandleTypeDef *huart;
RingBuffer_t rxRingBuffer;
RingBuffer_t txRingBuffer;
SemaphoreHandle_t txMutex;
SemaphoreHandle_t rxMutex;
SemaphoreHandle_t txSemaphore;
QueueHandle_t rxQueue;
uint8_t rxByte;
uint8_t txActive;
} UartManager_t;
/* 全局变量 */
#define UART_BUFFER_SIZE 256
static uint8_t uart1_rx_buffer[UART_BUFFER_SIZE];
static uint8_t uart1_tx_buffer[UART_BUFFER_SIZE];
static UartManager_t uart1_manager;
/* 环形缓冲区操作函数 */
void RingBuffer_Init(RingBuffer_t *rb, uint8_t *buffer, uint16_t size) {
rb->buffer = buffer;
rb->head = 0;
rb->tail = 0;
rb->size = size;
rb->count = 0;
}
uint8_t RingBuffer_Put(RingBuffer_t *rb, uint8_t data) {
if (rb->count >= rb->size) {
return 0; // 缓冲区满
}
rb->buffer[rb->head] = data;
rb->head = (rb->head + 1) % rb->size;
rb->count++;
return 1;
}
uint8_t RingBuffer_Get(RingBuffer_t *rb, uint8_t *data) {
if (rb->count == 0) {
return 0; // 缓冲区空
}
*data = rb->buffer[rb->tail];
rb->tail = (rb->tail + 1) % rb->size;
rb->count--;
return 1;
}
uint16_t RingBuffer_GetCount(RingBuffer_t *rb) {
return rb->count;
}
uint8_t RingBuffer_IsEmpty(RingBuffer_t *rb) {
return (rb->count == 0);
}
uint8_t RingBuffer_IsFull(RingBuffer_t *rb) {
return (rb->count >= rb->size);
}
/* UART管理器初始化 */
void UartManager_Init(UartManager_t *mgr, UART_HandleTypeDef *huart) {
mgr->huart = huart;
// 初始化环形缓冲区
RingBuffer_Init(&mgr->rxRingBuffer, uart1_rx_buffer, UART_BUFFER_SIZE);
RingBuffer_Init(&mgr->txRingBuffer, uart1_tx_buffer, UART_BUFFER_SIZE);
// 创建互斥量
mgr->txMutex = xSemaphoreCreateMutex();
mgr->rxMutex = xSemaphoreCreateMutex();
// 创建信号量
mgr->txSemaphore = xSemaphoreCreateBinary();
// 创建队列用于接收数据通知
mgr->rxQueue = xQueueCreate(10, sizeof(uint8_t));
mgr->txActive = 0;
// 启动UART接收中断
HAL_UART_Receive_IT(mgr->huart, &mgr->rxByte, 1);
}
/* UART发送函数 - 支持多任务安全 */
HAL_StatusTypeDef UartManager_Transmit(UartManager_t *mgr, uint8_t *data, uint16_t len, uint32_t timeout) {
HAL_StatusTypeDef status = HAL_OK;
uint16_t i;
// 获取发送互斥量
if (xSemaphoreTake(mgr->txMutex, pdMS_TO_TICKS(timeout)) != pdTRUE) {
return HAL_TIMEOUT;
}
// 将数据放入发送缓冲区
for (i = 0; i < len; i++) {
if (!RingBuffer_Put(&mgr->txRingBuffer, data[i])) {
status = HAL_ERROR; // 缓冲区满
break;
}
}
// 如果发送器空闲,启动发送
if (!mgr->txActive && !RingBuffer_IsEmpty(&mgr->txRingBuffer)) {
uint8_t txData;
if (RingBuffer_Get(&mgr->txRingBuffer, &txData)) {
mgr->txActive = 1;
HAL_UART_Transmit_IT(mgr->huart, &txData, 1);
}
}
// 等待发送完成
if (status == HAL_OK) {
xSemaphoreTake(mgr->txSemaphore, pdMS_TO_TICKS(timeout));
}
// 释放互斥量
xSemaphoreGive(mgr->txMutex);
return status;
}
/* UART接收函数 - 支持多任务安全 */
uint16_t UartManager_Receive(UartManager_t *mgr, uint8_t *data, uint16_t maxLen, uint32_t timeout) {
uint16_t received = 0;
uint8_t rxData;
TickType_t startTime = xTaskGetTickCount();
// 获取接收互斥量
if (xSemaphoreTake(mgr->rxMutex, pdMS_TO_TICKS(timeout)) != pdTRUE) {
return 0;
}
while (received < maxLen) {
// 从环形缓冲区获取数据
if (RingBuffer_Get(&mgr->rxRingBuffer, &rxData)) {
data[received++] = rxData;
} else {
// 缓冲区为空,等待新数据
if (xQueueReceive(mgr->rxQueue, &rxData, pdMS_TO_TICKS(10)) == pdTRUE) {
data[received++] = rxData;
} else {
// 检查超时
if ((xTaskGetTickCount() - startTime) >= pdMS_TO_TICKS(timeout)) {
break;
}
}
}
}
// 释放互斥量
xSemaphoreGive(mgr->rxMutex);
return received;
}
/* UART中断回调函数 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (huart == uart1_manager.huart) {
// 将接收到的数据放入环形缓冲区
if (RingBuffer_Put(&uart1_manager.rxRingBuffer, uart1_manager.rxByte)) {
// 通知接收队列有新数据
xQueueSendFromISR(uart1_manager.rxQueue, &uart1_manager.rxByte, &xHigherPriorityTaskWoken);
}
// 继续接收下一个字节
HAL_UART_Receive_IT(uart1_manager.huart, &uart1_manager.rxByte, 1);
}
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
uint8_t txData;
if (huart == uart1_manager.huart) {
// 检查发送缓冲区是否还有数据
if (RingBuffer_Get(&uart1_manager.txRingBuffer, &txData)) {
HAL_UART_Transmit_IT(uart1_manager.huart, &txData, 1);
} else {
// 发送完成
uart1_manager.txActive = 0;
xSemaphoreGiveFromISR(uart1_manager.txSemaphore, &xHigherPriorityTaskWoken);
}
}
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
/* 任务示例 */
void UartSendTask(void *pvParameters) {
char message[64];
uint8_t counter = 0;
while (1) {
snprintf(message, sizeof(message), "Send Task: Message %d\r\n", counter++);
if (UartManager_Transmit(&uart1_manager, (uint8_t*)message, strlen(message), 1000) != HAL_OK) {
// 发送失败处理
}
vTaskDelay(pdMS_TO_TICKS(2000));
}
}
void UartReceiveTask(void *pvParameters) {
uint8_t rxBuffer[128];
uint16_t rxLen;
while (1) {
rxLen = UartManager_Receive(&uart1_manager, rxBuffer, sizeof(rxBuffer) - 1, 1000);
if (rxLen > 0) {
rxBuffer[rxLen] = '\0';
// 处理接收到的数据
char response[64];
snprintf(response, sizeof(response), "Received: %s", rxBuffer);
UartManager_Transmit(&uart1_manager, (uint8_t*)response, strlen(response), 1000);
}
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void UartLogTask(void *pvParameters) {
char logMessage[64];
uint32_t logCounter = 0;
while (1) {
snprintf(logMessage, sizeof(logMessage), "Log: System running, count=%lu\r\n", logCounter++);
if (UartManager_Transmit(&uart1_manager, (uint8_t*)logMessage, strlen(logMessage), 1000) != HAL_OK) {
// 日志发送失败处理
}
vTaskDelay(pdMS_TO_TICKS(5000));
}
}
/* 主函数中的初始化 */
void UartMultiTask_Init(UART_HandleTypeDef *huart) {
// 初始化UART管理器
UartManager_Init(&uart1_manager, huart);
// 创建任务
xTaskCreate(UartSendTask, "UartSend", 256, NULL, 2, NULL);
xTaskCreate(UartReceiveTask, "UartReceive", 256, NULL, 3, NULL);
xTaskCreate(UartLogTask, "UartLog", 256, NULL, 1, NULL);
}
/* 错误处理函数 */
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {
if (huart == uart1_manager.huart) {
// 重新启动接收
HAL_UART_Receive_IT(uart1_manager.huart, &uart1_manager.rxByte, 1);
}
}
/* 获取UART状态信息 */
void UartManager_GetStatus(UartManager_t *mgr) {
char statusMsg[128];
snprintf(statusMsg, sizeof(statusMsg),
"UART Status: RX Count=%d, TX Count=%d, TX Active=%d\r\n",
RingBuffer_GetCount(&mgr->rxRingBuffer),
RingBuffer_GetCount(&mgr->txRingBuffer),
mgr->txActive);
UartManager_Transmit(mgr, (uint8_t*)statusMsg, strlen(statusMsg), 1000);
}
为STM32 FreeRTOS UART多任务系统增加了完整的printf支持。新增的功能包括:
Printf支持特性
1. 标准printf重定向
- 重写了
_write
函数,将printf输出重定向到UART - 使用专用互斥量
g_printf_mutex
保证多任务printf线程安全 - 避免多任务同时printf造成的输出混乱
2. 线程安全的Printf函数
UartManager_Printf()
: 支持格式化输出的线程安全版本- 使用环形缓冲区机制,与其他UART操作协调
- 提供
SAFE_PRINTF
宏定义,使用更便捷
3. 两种使用方式
标准printf方式:
c
printf("Send Task: Message %d\r\n", counter);
printf("System running, count=%lu, free heap=%lu\r\n",
logCounter, xPortGetFreeHeapSize());
线程安全printf方式:
c
SAFE_PRINTF(&uart1_manager, "Send Task: Message %d\r\n", counter);
UartManager_Printf(&uart1_manager, "Log: %s\r\n", message);
关键改进
1. 互斥量保护
- 专用的printf互斥量避免输出混乱
- 超时机制防止任务长时间阻塞
2. 缓冲区管理
- 256字节静态缓冲区用于格式化
- 自动长度限制防止缓冲区溢出
3. 错误处理
- 返回实际输出字节数
- 超时和错误情况的适当处理
使用示例
初始化时只需调用:
c
UartMultiTask_Init(&huart1); // 会自动设置printf输出
之后在任何任务中都可以直接使用printf:
c
printf("Task %s: Value = %d\r\n", pcTaskGetName(NULL), value);
这样就实现了完整的printf支持,既保持了标准C库的使用习惯,又确保了多任务环境下的线程安全性。
c
/* STM32 FreeRTOS UART多任务同步实现 */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "queue.h"
#include "stm32f4xx_hal.h"
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
/* 环形缓冲区结构 */
typedef struct {
uint8_t *buffer;
uint16_t head;
uint16_t tail;
uint16_t size;
uint16_t count;
} RingBuffer_t;
/* UART管理结构 */
typedef struct {
UART_HandleTypeDef *huart;
RingBuffer_t rxRingBuffer;
RingBuffer_t txRingBuffer;
SemaphoreHandle_t txMutex;
SemaphoreHandle_t rxMutex;
SemaphoreHandle_t txSemaphore;
QueueHandle_t rxQueue;
uint8_t rxByte;
uint8_t txActive;
} UartManager_t;
/* 全局变量 */
#define UART_BUFFER_SIZE 256
static uint8_t uart1_rx_buffer[UART_BUFFER_SIZE];
static uint8_t uart1_tx_buffer[UART_BUFFER_SIZE];
static UartManager_t uart1_manager;
/* 环形缓冲区操作函数 */
void RingBuffer_Init(RingBuffer_t *rb, uint8_t *buffer, uint16_t size) {
rb->buffer = buffer;
rb->head = 0;
rb->tail = 0;
rb->size = size;
rb->count = 0;
}
uint8_t RingBuffer_Put(RingBuffer_t *rb, uint8_t data) {
if (rb->count >= rb->size) {
return 0; // 缓冲区满
}
rb->buffer[rb->head] = data;
rb->head = (rb->head + 1) % rb->size;
rb->count++;
return 1;
}
uint8_t RingBuffer_Get(RingBuffer_t *rb, uint8_t *data) {
if (rb->count == 0) {
return 0; // 缓冲区空
}
*data = rb->buffer[rb->tail];
rb->tail = (rb->tail + 1) % rb->size;
rb->count--;
return 1;
}
uint16_t RingBuffer_GetCount(RingBuffer_t *rb) {
return rb->count;
}
uint8_t RingBuffer_IsEmpty(RingBuffer_t *rb) {
return (rb->count == 0);
}
uint8_t RingBuffer_IsFull(RingBuffer_t *rb) {
return (rb->count >= rb->size);
}
/* UART管理器初始化 */
void UartManager_Init(UartManager_t *mgr, UART_HandleTypeDef *huart) {
mgr->huart = huart;
// 初始化环形缓冲区
RingBuffer_Init(&mgr->rxRingBuffer, uart1_rx_buffer, UART_BUFFER_SIZE);
RingBuffer_Init(&mgr->txRingBuffer, uart1_tx_buffer, UART_BUFFER_SIZE);
// 创建互斥量
mgr->txMutex = xSemaphoreCreateMutex();
mgr->rxMutex = xSemaphoreCreateMutex();
// 创建信号量
mgr->txSemaphore = xSemaphoreCreateBinary();
// 创建队列用于接收数据通知
mgr->rxQueue = xQueueCreate(10, sizeof(uint8_t));
mgr->txActive = 0;
// 启动UART接收中断
HAL_UART_Receive_IT(mgr->huart, &mgr->rxByte, 1);
}
/* UART发送函数 - 支持多任务安全 */
HAL_StatusTypeDef UartManager_Transmit(UartManager_t *mgr, uint8_t *data, uint16_t len, uint32_t timeout) {
HAL_StatusTypeDef status = HAL_OK;
uint16_t i;
// 获取发送互斥量
if (xSemaphoreTake(mgr->txMutex, pdMS_TO_TICKS(timeout)) != pdTRUE) {
return HAL_TIMEOUT;
}
// 将数据放入发送缓冲区
for (i = 0; i < len; i++) {
if (!RingBuffer_Put(&mgr->txRingBuffer, data[i])) {
status = HAL_ERROR; // 缓冲区满
break;
}
}
// 如果发送器空闲,启动发送
if (!mgr->txActive && !RingBuffer_IsEmpty(&mgr->txRingBuffer)) {
uint8_t txData;
if (RingBuffer_Get(&mgr->txRingBuffer, &txData)) {
mgr->txActive = 1;
HAL_UART_Transmit_IT(mgr->huart, &txData, 1);
}
}
// 等待发送完成
if (status == HAL_OK) {
xSemaphoreTake(mgr->txSemaphore, pdMS_TO_TICKS(timeout));
}
// 释放互斥量
xSemaphoreGive(mgr->txMutex);
return status;
}
/* UART接收函数 - 支持多任务安全 */
uint16_t UartManager_Receive(UartManager_t *mgr, uint8_t *data, uint16_t maxLen, uint32_t timeout) {
uint16_t received = 0;
uint8_t rxData;
TickType_t startTime = xTaskGetTickCount();
// 获取接收互斥量
if (xSemaphoreTake(mgr->rxMutex, pdMS_TO_TICKS(timeout)) != pdTRUE) {
return 0;
}
while (received < maxLen) {
// 从环形缓冲区获取数据
if (RingBuffer_Get(&mgr->rxRingBuffer, &rxData)) {
data[received++] = rxData;
} else {
// 缓冲区为空,等待新数据
if (xQueueReceive(mgr->rxQueue, &rxData, pdMS_TO_TICKS(10)) == pdTRUE) {
data[received++] = rxData;
} else {
// 检查超时
if ((xTaskGetTickCount() - startTime) >= pdMS_TO_TICKS(timeout)) {
break;
}
}
}
}
// 释放互斥量
xSemaphoreGive(mgr->rxMutex);
return received;
}
/* UART中断回调函数 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
if (huart == uart1_manager.huart) {
// 将接收到的数据放入环形缓冲区
if (RingBuffer_Put(&uart1_manager.rxRingBuffer, uart1_manager.rxByte)) {
// 通知接收队列有新数据
xQueueSendFromISR(uart1_manager.rxQueue, &uart1_manager.rxByte, &xHigherPriorityTaskWoken);
}
// 继续接收下一个字节
HAL_UART_Receive_IT(uart1_manager.huart, &uart1_manager.rxByte, 1);
}
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart) {
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
uint8_t txData;
if (huart == uart1_manager.huart) {
// 检查发送缓冲区是否还有数据
if (RingBuffer_Get(&uart1_manager.txRingBuffer, &txData)) {
HAL_UART_Transmit_IT(uart1_manager.huart, &txData, 1);
} else {
// 发送完成
uart1_manager.txActive = 0;
xSemaphoreGiveFromISR(uart1_manager.txSemaphore, &xHigherPriorityTaskWoken);
}
}
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
}
/* 任务示例 */
void UartSendTask(void *pvParameters) {
uint8_t counter = 0;
while (1) {
// 使用标准printf
printf("Send Task: Message %d\r\n", counter++);
// 或使用线程安全的printf
// SAFE_PRINTF(&uart1_manager, "Send Task: Message %d\r\n", counter++);
vTaskDelay(pdMS_TO_TICKS(2000));
}
}
void UartReceiveTask(void *pvParameters) {
uint8_t rxBuffer[128];
uint16_t rxLen;
while (1) {
rxLen = UartManager_Receive(&uart1_manager, rxBuffer, sizeof(rxBuffer) - 1, 1000);
if (rxLen > 0) {
rxBuffer[rxLen] = '\0';
// 使用printf处理接收到的数据
printf("Received: %s", rxBuffer);
// 也可以使用原来的发送函数
// char response[64];
// snprintf(response, sizeof(response), "Received: %s", rxBuffer);
// UartManager_Transmit(&uart1_manager, (uint8_t*)response, strlen(response), 1000);
}
vTaskDelay(pdMS_TO_TICKS(100));
}
}
void UartLogTask(void *pvParameters) {
uint32_t logCounter = 0;
while (1) {
// 使用printf输出系统日志
printf("Log: System running, count=%lu, free heap=%lu\r\n",
logCounter++, xPortGetFreeHeapSize());
vTaskDelay(pdMS_TO_TICKS(5000));
}
}
/* 主函数中的初始化 */
void UartMultiTask_Init(UART_HandleTypeDef *huart) {
// 初始化UART管理器
UartManager_Init(&uart1_manager, huart);
// 设置printf输出到UART
UartManager_SetPrintfUart(&uart1_manager);
// 创建任务
xTaskCreate(UartSendTask, "UartSend", 256, NULL, 2, NULL);
xTaskCreate(UartReceiveTask, "UartReceive", 256, NULL, 3, NULL);
xTaskCreate(UartLogTask, "UartLog", 256, NULL, 1, NULL);
}
/* 错误处理函数 */
void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {
if (huart == uart1_manager.huart) {
// 重新启动接收
HAL_UART_Receive_IT(uart1_manager.huart, &uart1_manager.rxByte, 1);
}
}
/* Printf支持相关变量和函数 */
static UartManager_t *g_printf_uart = NULL;
static SemaphoreHandle_t g_printf_mutex = NULL;
/* 设置Printf输出的UART */
void UartManager_SetPrintfUart(UartManager_t *mgr) {
g_printf_uart = mgr;
// 创建printf专用互斥量
if (g_printf_mutex == NULL) {
g_printf_mutex = xSemaphoreCreateMutex();
}
}
/* 重定向printf到UART - 支持多任务安全 */
int _write(int file, char *ptr, int len) {
if (g_printf_uart == NULL || g_printf_mutex == NULL) {
return -1;
}
// 获取printf互斥量,防止多任务同时printf造成输出混乱
if (xSemaphoreTake(g_printf_mutex, pdMS_TO_TICKS(1000)) == pdTRUE) {
// 直接发送到UART,不经过发送缓冲区避免死锁
HAL_StatusTypeDef status = HAL_UART_Transmit(g_printf_uart->huart, (uint8_t*)ptr, len, 1000);
xSemaphoreGive(g_printf_mutex);
return (status == HAL_OK) ? len : -1;
}
return -1;
}
/* 支持printf的安全版本 - 使用环形缓冲区 */
int UartManager_Printf(UartManager_t *mgr, const char *format, ...) {
static char printf_buffer[256];
va_list args;
int len;
// 获取printf互斥量
if (xSemaphoreTake(g_printf_mutex, pdMS_TO_TICKS(1000)) != pdTRUE) {
return -1;
}
// 格式化字符串
va_start(args, format);
len = vsnprintf(printf_buffer, sizeof(printf_buffer), format, args);
va_end(args);
// 限制长度
if (len >= sizeof(printf_buffer)) {
len = sizeof(printf_buffer) - 1;
}
// 发送数据
HAL_StatusTypeDef status = UartManager_Transmit(mgr, (uint8_t*)printf_buffer, len, 1000);
xSemaphoreGive(g_printf_mutex);
return (status == HAL_OK) ? len : -1;
}
/* 线程安全的printf宏定义 */
#define SAFE_PRINTF(mgr, fmt, ...) UartManager_Printf(mgr, fmt, ##__VA_ARGS__)
/* 获取UART状态信息 */
void UartManager_GetStatus(UartManager_t *mgr) {
printf("UART Status: RX Count=%d, TX Count=%d, TX Active=%d\r\n",
RingBuffer_GetCount(&mgr->rxRingBuffer),
RingBuffer_GetCount(&mgr->txRingBuffer),
mgr->txActive);
}