环境配置
项目使用STM32CubeMX初始化框架
IDE: JetBrains Clion 2025.1.1
编译环境使用arm-none-eabi-gcc
使用嘉立创天空星STM32F407VGT6开发板进行测试
提要
使用DMA+RingBuffer形式实现USART写入,减少主控占用,提高串口数据处理效率。
实现
usart.c文件内添加
/* USER CODE BEGIN 0 */
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#define UART_TX_BUFFER_SIZE 1024
static uint8_t uart_tx_buffer[UART_TX_BUFFER_SIZE];
static volatile uint16_t uart_tx_head = 0;
static volatile uint16_t uart_tx_tail = 0;
static volatile uint8_t uart_tx_dma_busy = 0;
static void uart_buffer_write(const uint8_t *data, uint16_t len)
{
for (uint16_t i = 0; i < len; i++) {
uint16_t next = (uart_tx_head + 1) % UART_TX_BUFFER_SIZE;
if (next == uart_tx_tail) {
// 缓冲区满,丢弃
break;
}
uart_tx_buffer[uart_tx_head] = data[i];
uart_tx_head = next;
}
if (!uart_tx_dma_busy) {
uint16_t count = (uart_tx_head >= uart_tx_tail)
? uart_tx_head - uart_tx_tail
: UART_TX_BUFFER_SIZE - uart_tx_tail;
if (count > 0) {
uart_tx_dma_busy = 1;
HAL_UART_Transmit_DMA(&huart1, &uart_tx_buffer[uart_tx_tail], count);
}
}
}
void uart_tx_dma_callback(UART_HandleTypeDef *huart)
{
if (huart->Instance != USART1) return;
uint16_t count = (uart_tx_head >= uart_tx_tail)
? uart_tx_head - uart_tx_tail
: UART_TX_BUFFER_SIZE - uart_tx_tail;
uart_tx_tail = (uart_tx_tail + count) % UART_TX_BUFFER_SIZE;
if (uart_tx_tail != uart_tx_head) {
count = (uart_tx_head > uart_tx_tail)
? uart_tx_head - uart_tx_tail
: UART_TX_BUFFER_SIZE - uart_tx_tail;
HAL_UART_Transmit_DMA(&huart1, &uart_tx_buffer[uart_tx_tail], count);
} else {
uart_tx_dma_busy = 0;
}
}
/* USER CODE END 0 */
/* USER CODE BEGIN 1 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
extern void uart_tx_dma_callback(UART_HandleTypeDef *huart); // 声明 usart.c 中写的回调函数
uart_tx_dma_callback(huart); // 调用定义的环形缓冲区管理函数
}
void uart_printf(const char *fmt, ...)
{
char tmp[128]; // 临时格式化缓冲区
va_list args;
va_start(args, fmt);
int len = vsnprintf(tmp, sizeof(tmp), fmt, args);
va_end(args);
if (len > 0)
{
uart_buffer_write((uint8_t *)tmp, len); // 一次性写入全部格式化字符串
}
}
/* USER CODE END 1 */
usart.h文件内添加
/* USER CODE BEGIN Prototypes */
void uart_tx_dma_callback(UART_HandleTypeDef *huart);
extern void uart_printf(const char *fmt, ...);
/* USER CODE END Prototypes */
CMakeList.txt文件内添加
target_link_options(${CMAKE_PROJECT_NAME} PRIVATE
-Wl,-u,_printf_float
-Wl,-u,_scanf_float //启用串口浮点支持
)