Skip to content
c
#ifndef __USART_H__
#define __USART_H__

#ifdef __cplusplus
extern "C"
{
#endif

#include "main.h"

/*------------------变量和宏-----------------------*/
extern UART_HandleTypeDef huart1; // UART1句柄
extern DMA_HandleTypeDef hdma_usart1_rx;  // DMA接收句柄

#define RX_BUFFER_SIZE 128 // 接收缓冲区大小
extern uint8_t rxBuffer[RX_BUFFER_SIZE]; // 接收缓冲区
extern volatile uint8_t commandReady; // 完成标志
extern volatile uint16_t rxLength;    // 实际接收到的数据长度

/*------------------函数声明-----------------------*/

// 初始化DMA
void MX_DMA_Init(void);

// 初始化UART1
void MX_USART1_UART_Init(void);

// 自定义空闲中断处理函数
void UASART_EDLE_Interrupt(UART_HandleTypeDef *huart);

// 解析命令
void ParseCommand(uint8_t *command);


#ifdef __cplusplus
}
#endif

#endif /* __USART_H__ */
c
#include "usart.h"
#include <string.h>
#include <stdio.h>

UART_HandleTypeDef huart1;
DMA_HandleTypeDef hdma_usart1_rx;

uint8_t rxBuffer[RX_BUFFER_SIZE];
volatile uint8_t commandReady = 0;
volatile uint16_t rxLength = 0;

/*------------------------功能函数------------------------------*/

// 重定向printf到USART1
int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
    return ch;
}

// 解析接收到的命令
void ParseCommand(uint8_t *command)
{
    // 处理命令
    if (strcmp((char *)command, "LED_ON") == 0)
    {
        printf("LED ON\r\n");
        // 在这里添加LED开启的代码
        // HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
    }
    else if (strcmp((char *)command, "LED_OFF") == 0)
    {
        printf("LED OFF\r\n");
        // 在这里添加LED关闭的代码
        // HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
    }
    else if (strcmp((char *)command, "STATUS") == 0)
    {
        printf("System OK, Received: %d bytes\r\n", rxLength);
    }
    else if (rxLength > 0) // 只有接收到数据才提示未知命令
    {
        printf("UNKNOWN COMMAND: %s (len=%d)\r\n", command, rxLength);
    }
}

/*------------------------中断服务函数(自包含)------------------------------*/

// USART1中断服务函数 - 包含空闲中断处理
void USART1_IRQHandler(void)
{
    // 处理标准 UART 中断
    HAL_UART_IRQHandler(&huart1);

    // 处理空闲中断
    if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
    {
        UASART_EDLE_Interrupt(&huart1);
    }
}


// 自定义的函数(没有提供默认的空闲中断回调)
void UASART_EDLE_Interrupt(UART_HandleTypeDef *huart)
{
    // 清除空闲中断标志
    __HAL_UART_CLEAR_IDLEFLAG(huart);
    // 停止 DMA 传输
    HAL_UART_DMAStop(huart);
    // 计算实际接收到的数据长度
    rxLength = RX_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(huart->hdmarx);
    // 如果接收到了有效数据
    if (rxLength > 0)
    {
        // 去除末尾的换行符或回车符
        while (rxLength > 0 && (rxBuffer[rxLength - 1] == '\r' || rxBuffer[rxLength - 1] == '\n'))
        {
            rxBuffer[--rxLength] = '\0';
        }
        // 设置命令准备标志
        commandReady = 1;
    }
    // 重新启动 DMA 接收
    HAL_UART_Receive_DMA(huart, rxBuffer, RX_BUFFER_SIZE);
}

/*------------------------初始化函数------------------------------*/

// DMA初始化函数
void MX_DMA_Init(void)
{
    // 使能DMA1时钟
    __HAL_RCC_DMA1_CLK_ENABLE();

    // 配置DMA1_Channel5中断优先级
    HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 6, 0);
    HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);
}

// USART1初始化函数
void MX_USART1_UART_Init(void)
{
    // 初始化USART1参数
    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();
    }

    printf("USART1 + DMA + IDLE Self-Contained Module Initialized\r\n");

    // 清空接收缓冲区
    memset(rxBuffer, 0, RX_BUFFER_SIZE);

    // 启用空闲中断
    __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);

    // 启动DMA接收
    HAL_UART_Receive_DMA(&huart1, rxBuffer, RX_BUFFER_SIZE);
}

// UART MSP初始化函数
void HAL_UART_MspInit(UART_HandleTypeDef *uartHandle)
{
    GPIO_InitTypeDef GPIO_InitStruct = {0};

    // 判断是哪个USART
    if (uartHandle->Instance == USART1)
    {
        // 使能时钟
        __HAL_RCC_USART1_CLK_ENABLE();
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_DMA1_CLK_ENABLE();

        /**USART1 GPIO配置 (STM32F103)
        PA9  ------> USART1_TX
        PA10 ------> USART1_RX
        */
        // TX引脚 - 复用推挽输出
        GPIO_InitStruct.Pin = GPIO_PIN_9;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        // RX引脚 - 浮空输入
        GPIO_InitStruct.Pin = GPIO_PIN_10;
        GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

        // 配置DMA
        hdma_usart1_rx.Instance = DMA1_Channel5;                       // 指定 DMA 通道为 DMA1_Channel5
        hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;          // 数据传输方向:从外设(USART1_RX)到内存
        hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;              // 外设地址不自增(固定为 USART1 数据寄存器地址)
        hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;                  // 内存地址自增(每接收一个字节,存储到下一个内存地址)
        hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE; // 外设数据对齐方式:字节对齐
        hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;    // 内存数据对齐方式:字节对齐
        hdma_usart1_rx.Init.Mode = DMA_CIRCULAR;                       // 配置为循环模式,DMA 传输结束后自动从头开始
        hdma_usart1_rx.Init.Priority = DMA_PRIORITY_MEDIUM;            // 设置 DMA 优先级为中等优先级

        // 初始化DMA
        if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK)
        {
            Error_Handler();
        }

        // 关联DMA和UART
        __HAL_LINKDMA(uartHandle, hdmarx, hdma_usart1_rx);

        // 配置USART1中断优先级
        HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
        HAL_NVIC_EnableIRQ(USART1_IRQn);
    }
}

// UART MSP解除初始化函数
void HAL_UART_MspDeInit(UART_HandleTypeDef *uartHandle)
{
    if (uartHandle->Instance == USART1)
    {
        // 禁用USART1时钟
        __HAL_RCC_USART1_CLK_DISABLE();

        // 解除GPIO初始化
        HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9 | GPIO_PIN_10);

        // 解除DMA关联
        HAL_DMA_DeInit(uartHandle->hdmarx);

        // 禁用中断
        HAL_NVIC_DisableIRQ(USART1_IRQn);
        HAL_NVIC_DisableIRQ(DMA1_Channel5_IRQn);
    }
}