前言

  1. 本次测试基于GD32F425RGT6核心板
  2. 驱动暂时只编写了USART0,其余的可以参考实现的
  3. 驱动编写参考官方手册和官方库提供的标准库里的示例程序

串口驱动

驱动头文件

/**
  ******************************************************************************
  * @file           : drv_usart.h
  * @author         : shchl
  * @brief          : None
  * @attention      : None
  * @date           : 2026/3/18
  ******************************************************************************
  */

#ifndef GD32F425_PROJECT_DRV_USART_H
#define GD32F425_PROJECT_DRV_USART_H

void DrvUsartInit(void);

int SerialInit(uint32_t usart_periph);
int SerialStart(uint32_t usart_periph, uint32_t baud);
int SerialSendAsync(uint32_t usart_periph,uint8_t* buf, uint16_t len, int32_t timeout);
int SerialRecv(uint32_t usart_periph, uint8_t* buf, uint16_t len, int32_t timeout);

#endif //GD32F425_PROJECT_DRV_USART_H

源文件

/**
  ******************************************************************************
  * @file           : drv_usart.c
  * @author         : shchl
  * @brief          : None
  * @attention      : None
  * @date           : 2026/3/18
  ******************************************************************************
  */
#include "drivers.h"
#include "drv_usart.h"
#define USART_RX_EVT 0x01 // 接收到数据
#define USART_TX_EVT 0x02 // 发送完成

#define USART_RS_TX_MODE 0
#define USART_RS_RX_MODE 1


#define U0_RS_ENABLE  1
#define U0_RS_CLK   RCU_GPIOA
#define U0_RS_PORT  GPIOA
#define U0_RS_PIN   GPIO_PIN_8
#define U0_CACHE_BUF_LEN     256
#define U0_DMA DMA1
#define U0_RX_DMA_CH DMA_CH2
#define U0_TX_DMA_CH DMA_CH7


#define U1_RS_ENABLE  1
#define U1_RS_CLK   RCU_GPIOB
#define U1_RS_PORT  GPIOB
#define U1_RS_PIN   GPIO_PIN_7
#define U1_CACHE_BUF_LEN     256

#define U2_RS_ENABLE  1
#define U2_RS_CLK   RCU_GPIOB
#define U2_RS_PORT  GPIOB
#define U2_RS_PIN   GPIO_PIN_7
#define U2_CACHE_BUF_LEN     256

typedef struct
{
    uint32_t instance;
    osEventFlagsId_t evtHandle;
    struct rt_ringbuffer rxRb;

    uint8_t* pRxBuf;
    uint8_t* pRbBuf;
    uint16_t rxBufLen;
    uint16_t rbBufLen;
    uint8_t isInit;
} SerialDriver_t;

static uint8_t u0RxBuf[U0_CACHE_BUF_LEN] = {0};
static uint8_t u0RxRbBuf[U0_CACHE_BUF_LEN * 2] = {0};


static SerialDriver_t u0 = {
    .instance = USART0,
    .evtHandle = NULL,
    .pRbBuf = u0RxRbBuf,
    .pRxBuf = u0RxBuf,
    .rxBufLen = sizeof(u0RxBuf),
    .rbBufLen = sizeof(u0RxRbBuf),
    .isInit = 0,
};
static uint8_t u1RxBuf[U1_CACHE_BUF_LEN] = {0};
static uint8_t u1RxRbBuf[U1_CACHE_BUF_LEN * 2] = {0};
static SerialDriver_t u1 = {
    .instance = USART1,
    .evtHandle = NULL,
    .pRbBuf = u1RxRbBuf,
    .pRxBuf = u1RxBuf,
    .rxBufLen = sizeof(u1RxBuf),
    .rbBufLen = sizeof(u1RxRbBuf),
    .isInit = 0,
};

static uint8_t u2RxBuf[U2_CACHE_BUF_LEN] = {0};
static uint8_t u2RxRbBuf[U2_CACHE_BUF_LEN * 2] = {0};
static SerialDriver_t u2 = {
    .instance = USART2,
    .evtHandle = NULL,
    .pRbBuf = u2RxRbBuf,
    .pRxBuf = u2RxBuf,
    .rxBufLen = sizeof(u2RxBuf),
    .rbBufLen = sizeof(u2RxRbBuf),
    .isInit = 0,
};

static SerialDriver_t* GetSerialDriver(uint32_t usart_periph)
{
    if (usart_periph == USART0)
        return &u0;
    if (usart_periph == USART1)
        return &u1;
    if (usart_periph == USART2)
        return &u2;
    return NULL;
}


void DrvUsartInit(void)
{
    SerialInit(USART0);
}

/**
 *
 * @param usart_periph
 * @param mode 1:接收 0:发送
 */
static void instance_set_mode(uint32_t usart_periph, uint8_t mode)
{
#if U0_RS_ENABLE
    if (usart_periph == USART0)
    {
        gpio_bit_write(U0_RS_PORT,U0_RS_PIN, mode ? RESET : SET);
    }
    else
#endif // U0_RS_ENABLE
#if U2_RS_ENABLE
        if (usart_periph == USART2)
        {
            gpio_bit_write(U2_RS_PORT,U2_RS_PIN, mode ? RESET : SET);
        }
#endif
}


int SerialInit(uint32_t usart_periph)
{
    SerialDriver_t* pSerial = GetSerialDriver(usart_periph);
    assert(pSerial);
    if (pSerial->isInit)
    {
        return 0;
    }
    pSerial->evtHandle = osEventFlagsNew(NULL);
    if (!pSerial->evtHandle)
    {
        return -1;
    }
    rt_ringbuffer_init(&pSerial->rxRb, pSerial->pRbBuf, pSerial->rbBufLen);


    if (usart_periph == USART0)
    {
        //============================NVIC==========================
        nvic_irq_enable(USART0_IRQn, 5, 0);
        //===========================时钟初始化==========================
        rcu_periph_clock_enable(RCU_DMA1);
        rcu_periph_clock_enable(RCU_GPIOA);
        rcu_periph_clock_enable(RCU_USART0);
        //===========================引脚初始化==========================
        gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9); // TX
        gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10); // RX
        gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
        gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
        gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
        gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
#if U0_RS_ENABLE
        rcu_periph_clock_enable(U0_RS_CLK);
        gpio_mode_set(U0_RS_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, U0_RS_PIN);
        gpio_output_options_set(U0_RS_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, U0_RS_PIN);
#endif
        // ===========================串口初始化==========================
        usart_deinit(USART0);
        usart_baudrate_set(USART0, 115200U);
        usart_receive_config(USART0, USART_RECEIVE_ENABLE);
        usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
        usart_enable(USART0);
        // ===========================DMA初始化==========================
        usart_dma_receive_config(USART0, USART_RECEIVE_DMA_ENABLE);
        usart_dma_transmit_config(USART0, USART_TRANSMIT_DMA_ENABLE);
        //============================DMA初始化(TX)==========================
        dma_single_data_parameter_struct dma_param;
        // 参数默认初始化
        dma_single_data_para_struct_init(&dma_param);

        dma_deinit(U0_DMA, U0_TX_DMA_CH);
        dma_param.direction = DMA_MEMORY_TO_PERIPH;
        // dma_param.memory0_addr = (uint32_t)txBuf;
        // dma_param.number = sizeof(txBuf);
        dma_param.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
        dma_param.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
        dma_param.periph_addr = ((uint32_t)&USART_DATA(USART0));
        dma_param.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
        dma_param.priority = DMA_PRIORITY_ULTRA_HIGH;
        dma_single_data_mode_init(U0_DMA, U0_TX_DMA_CH, &dma_param);
        dma_circulation_disable(U0_DMA, U0_TX_DMA_CH);
        dma_switch_buffer_mode_enable(U0_DMA, U0_TX_DMA_CH, DISABLE);
        dma_channel_subperipheral_select(U0_DMA, U0_TX_DMA_CH, DMA_SUBPERI4);
        // 开启串口完成中断
        usart_interrupt_enable(USART0, USART_INT_TC);
        // ============================DMA初始化(RX)==========================
        dma_deinit(U0_DMA, U0_RX_DMA_CH);
        dma_param.direction = DMA_PERIPH_TO_MEMORY;
        dma_param.memory0_addr = (uint32_t)pSerial->pRxBuf;
        dma_param.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
        dma_param.number = pSerial->rxBufLen;
        dma_param.periph_addr = ((uint32_t)&USART_DATA(USART0));
        dma_param.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
        dma_param.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
        dma_param.priority = DMA_PRIORITY_ULTRA_HIGH;
        dma_single_data_mode_init(U0_DMA, U0_RX_DMA_CH, &dma_param);
        dma_switch_buffer_mode_enable(U0_DMA, U0_RX_DMA_CH, DISABLE);
        dma_circulation_disable(U0_DMA, U0_RX_DMA_CH);
        dma_channel_subperipheral_select(U0_DMA, U0_RX_DMA_CH, DMA_SUBPERI4);
        dma_channel_enable(U0_DMA, U0_RX_DMA_CH);
    }
    else if (usart_periph == USART1)
    {
    }
    else if (usart_periph == USART2)
    {
        nvic_irq_enable(USART2_IRQn, 5, 0);
        rcu_periph_clock_enable(RCU_DMA1);
    }
    else
    {
        return -2;
    }


    pSerial->isInit = 1;
    return 0;
}

int SerialStart(uint32_t usart_periph, uint32_t baud)
{
    SerialDriver_t* pSerial = GetSerialDriver(usart_periph);
    assert(pSerial);
    if (!pSerial->isInit) return -1;

    // USART使能(UEN=0)
    usart_disable(usart_periph);
    // 设置波特率;使能USART(UEN=1)时,不能写该寄存器。
    usart_baudrate_set(usart_periph, baud);
    // USART使能(UEN=1)
    usart_enable(usart_periph);
    // 开启串口空闲中断
    usart_interrupt_enable(usart_periph, USART_INT_IDLE);

    instance_set_mode(usart_periph, USART_RS_RX_MODE);
    return 0;
}

int SerialSendAsync(uint32_t usart_periph, uint8_t* buf, uint16_t len, int32_t timeout)
{
    SerialDriver_t* pSerial = GetSerialDriver(usart_periph);
    assert(pSerial);
    if (!pSerial->isInit) return -1;
    instance_set_mode(usart_periph, USART_RS_TX_MODE);
    if (usart_periph == USART0)
    {
        // 停止DMA
        dma_channel_disable(U0_DMA, U0_TX_DMA_CH);
        // 设置DMA传输地址
        dma_memory_address_config(U0_DMA,U0_TX_DMA_CH, DMA_MEMORY_0, (uint32_t)buf);
        dma_transfer_number_config(U0_DMA, U0_TX_DMA_CH, len);
        // 启动DMA
        dma_channel_enable(U0_DMA, U0_TX_DMA_CH);
        // 等待发送完成
    }
    else
    {
        return -2;
    }

    const uint32_t flags = osEventFlagsWait(pSerial->evtHandle, USART_TX_EVT, osFlagsWaitAny, timeout);
    // 设置串口模式为接收模式
    instance_set_mode(usart_periph, USART_RS_RX_MODE);
    if (flags & USART_TX_EVT)
    {
        return len;
    }
    return 0;
}

int SerialRecv(uint32_t usart_periph, uint8_t* buf, uint16_t len, int32_t timeout)
{
    SerialDriver_t* pSerial = GetSerialDriver(usart_periph);
    assert(pSerial);
    if (!pSerial->isInit) return -1;

    if (usart_periph == USART0)
    {
    }
    else
    {
        return -2;
    }
    const uint32_t flags = osEventFlagsWait(pSerial->evtHandle, USART_RX_EVT, osFlagsWaitAny, timeout);
    if (flags & USART_RX_EVT)
    {
        return rt_ringbuffer_get(&pSerial->rxRb, buf, len);
    }
    else
    {
        // todo 错误处理
    }
    return rt_ringbuffer_get(&pSerial->rxRb, buf, len);
}


void USART0_IRQHandler(void)
{
    // 接收处理
    if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE) != RESET)
    {
        /* 清除接收标志位 */
        usart_data_receive(USART0);
        const uint16_t rx_len = U0_CACHE_BUF_LEN - dma_transfer_number_get(U0_DMA, U0_RX_DMA_CH);
        // 拷贝数据(缓存区)
        rt_ringbuffer_put_force(&u0.rxRb, u0.pRxBuf, rx_len);
        // todo 保存数据
        osEventFlagsSet(u0.evtHandle, USART_RX_EVT);
        dma_channel_disable(U0_DMA, U0_RX_DMA_CH);
        // 清除传输完成标志位,否则下次无法正常接收到数据
        dma_flag_clear(U0_DMA, U0_RX_DMA_CH, DMA_FLAG_FTF);
        //  重新配置缓存区配置
        dma_transfer_number_config(U0_DMA, U0_RX_DMA_CH, u0.rxBufLen);
        dma_channel_enable(U0_DMA, U0_RX_DMA_CH);
        dma_channel_enable(DMA1, U0_RX_DMA_CH);
    }
    // 发送处理
    else if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_TC) != RESET)
    {
        // 清除中断完成标志位
        usart_interrupt_flag_clear(USART0, USART_INT_FLAG_TC);
        // 传输完成,通知应用层
        osEventFlagsSet(u0.evtHandle, USART_TX_EVT);
        // 禁用DMA通道
        dma_channel_disable(U0_DMA, U0_TX_DMA_CH);
        // 清除对应的标志位
        dma_flag_clear(U0_DMA, U0_TX_DMA_CH, DMA_FLAG_FTF);
    }
    else
    {
        usart_data_receive(USART0);
    }
}

测试程序

/**
  ******************************************************************************
  * @file           : main.c
  * @author         : shchl
  * @brief          : None
  * @attention      : None
  * @date           : 2026/3/14
  ******************************************************************************
  */
#include "main.h"
#include "SEGGER.h"
#include "SEGGER_RTT.h"
#include "Service/ioctrl_service.h"

static void StartAppTask(void* argument);
static void CompLoggerInit(void* argument);

osThreadId_t appHandle;
const osThreadAttr_t appHandle_attributes = {
    .name = "App",
    .stack_size = 512 * 4,
    .priority = (osPriority_t)osPriorityNormal,
};
/**
 *   ck_sys:系统时钟频率(200MHz)
 *   ck_ahb:AHB时钟频率(200MHz)
 *   ck_apb1:APB1时钟频率(50MHz)
 *   ck_apb2:APB2时钟频率(100MHz)
 * @brief  应用程序入口函数.
 * @retval int
 */
int main(void)
{
    /* 设置NVIC优先级分组为4位抢占优先级,0位子优先级 */
    nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
    rcu_periph_clock_enable(RCU_SYSCFG);
    rcu_periph_clock_enable(RCU_GPIOA);
    rcu_periph_clock_enable(RCU_TIMER1);
    rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
    nvic_irq_enable(TIMER1_IRQn, 5, 0);
    nvic_irq_enable(USART0_IRQn, 5, 0); // USART0: 通信优先级,较高优先级

    //=============================================================================
    //============================================================================

#ifdef DEBUG
    SEGGER_RTT_Init();
#endif //  DEBUG

    // 初始化内核
    osKernelInitialize();
    // 创建主任务
    appHandle = osThreadNew(StartAppTask, NULL, &appHandle_attributes);
    /* Start scheduler */
    osKernelStart();

    while (1)
    {
    }
}


static void StartAppTask(void* argument)
{
    DriverInit();
    // 组件初始化
    CompLoggerInit(argument);
    // IO控制服务初始化
    IoCtrl_ServiceInit();


    IoCtrl_ServiceStart();

    IoCtrl_Led0Blink();
    DrvUsartInit();
    SerialStart(USART0, 115200);

    static uint8_t buf[128];
    for (;;)
    {
        int sz = SerialRecv(USART0, buf, sizeof(buf), osWaitForever);
        if (sz > 0)
        {
            SerialSendAsync(USART0, buf, sz, osWaitForever);
        }
        // log_d("Hello World!");
    }
}


/**
 * @brief 组件初始化(日志)
 * @param argument
 */
static void CompLoggerInit(void* argument)
{
    elog_init();
    elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);
    elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TIME);
    elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL & ~ELOG_FMT_FUNC & ~ELOG_FMT_DIR & ~ELOG_FMT_TAG);
    elog_set_filter_lvl(ELOG_LVL_DEBUG);
    elog_set_text_color_enabled(true); /*Eenbale color*/
    /* start EasyLogger */
    elog_start();
}

测试结果

在这里插入图片描述

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐