小华 HC32L130 串口中断发送 + DMA 发送 完整实现 + 性能对比

张开发
2026/4/17 20:42:56 15 分钟阅读

分享文章

小华 HC32L130 串口中断发送 + DMA 发送 完整实现 + 性能对比
目录一、基础环境说明二、共用初始化代码中断 / DMA 通用三、方式 1UART 中断方式发送完整实现1. 中断发送原理2. 完整代码3. 使用方法四、方式 2UART DMA 方式发送完整实现1. DMA 发送原理2. 完整代码3. 使用方法五、性能对比实测关键数据核心结论六、关键注意事项总结本文基于HC32L130 官方库提供UART 中断方式发送、UART DMA 方式发送的完整可运行代码并做实测性能对比适用于小华 MCU 低功耗串口数据发送场景。一、基础环境说明MCUHC32L130J8TA兼容 HC32L130 全系列库版本HC32L130_DDL_V1.0.0串口UART1TX:PA9RX:PA10最常用引脚时钟内部高速 RC 8MHz波特率115200可自由修改二、共用初始化代码中断 / DMA 通用所有发送方式都需要先初始化 UART、GPIO、时钟代码直接复制可用。#include hc32l130.h // UART1 TX:PA9 RX:PA10 #define UART1_TX_PORT GPIOA #define UART1_TX_PIN GPIO_PIN_9 #define UART1_RX_PORT GPIOA #define UART1_RX_PIN GPIO_PIN_10 // 全局发送缓冲区 uint8_t uart_send_buf[256] HC32L130 UART Test: Interrupt / DMA Mode\r\n; uint8_t send_len 0; // 串口初始化 void UART1_Init(void) { stc_gpio_cfg_t stcGpioCfg; stc_uart_cfg_t stcUartCfg; // 开启时钟 CLK_SetPeriClk(CLK_PERI_GPIO | CLK_PERI_UART1, ENABLE); // GPIO初始化 TX推挽输出 RX上拉输入 GPIO_StructInit(stcGpioCfg); stcGpioCfg.u16PinDir PIN_DIR_OUT; stcGpioCfg.u16PinAF PIN_FUNC_2; GPIO_Init(UART1_TX_PORT, UART1_TX_PIN, stcGpioCfg); stcGpioCfg.u16PinDir PIN_DIR_IN; stcGpioCfg.u16PullUp PIN_PU_ON; GPIO_Init(UART1_RX_PORT, UART1_RX_PIN, stcGpioCfg); // UART初始化 115200 8N1 UART_StructInit(stcUartCfg); stcUartCfg.u32BaudRate 115200; stcUartCfg.u32ClkSrc UART_CLK_PCLK; UART_Init(M0P_UART1, stcUartCfg); // 使能UART UART_Cmd(M0P_UART1, ENABLE); }三、方式 1UART 中断方式发送完整实现1. 中断发送原理使能发送完成中断TC启动发送第一个字节后硬件自动触发中断中断服务函数中逐字节发送直到全部发送完成2. 完整代码// 中断发送标志 volatile uint8_t uart_tx_busy 0; // UART1 中断服务函数 void UART1_IRQHandler(void) { // 发送完成中断 if(UART_GetIntFlag(M0P_UART1, UART_INT_TX_EMPTY)) { UART_ClearIntFlag(M0P_UART1, UART_INT_TX_EMPTY); static uint16_t cnt 0; cnt; if(cnt send_len) { // 继续发送下一字节 UART_SendData(M0P_UART1, uart_send_buf[cnt]); } else { // 发送完成 关闭中断 清除标志 UART_IntCmd(M0P_UART1, UART_INT_TX_EMPTY, DISABLE); uart_tx_busy 0; cnt 0; } } } // 中断方式发送函数 void UART1_IT_SendData(uint8_t *buf, uint16_t len) { if(uart_tx_busy 1) return; // 忙则退出 uart_tx_busy 1; send_len len; // 使能发送空中断 UART_IntCmd(M0P_UART1, UART_INT_TX_EMPTY, ENABLE); // 发送第一个字节 UART_SendData(M0P_UART1, buf[0]); // 配置中断优先级并使能中断 NVIC_ClearPendingIRQ(UART1_IRQn); NVIC_SetPriority(UART1_IRQn, 3); NVIC_EnableIRQ(UART1_IRQn); }3. 使用方法int main(void) { UART1_Init(); uint8_t test_buf[] Hello HC32L130 UART Interrupt Mode!\r\n; while(1) { // 中断发送 UART1_IT_SendData(test_buf, sizeof(test_buf)); delay_ms(1000); } }四、方式 2UART DMA 方式发送完整实现1. DMA 发送原理配置 DMA 内存到外设模式DMA 自动从内存搬运数据到 UART 数据寄存器CPU 完全不干预发送完成后触发 DMA 完成中断2. 完整代码// DMA发送完成标志 volatile uint8_t dma_tx_done 0; // DMA初始化UART1 TX 对应 DMA通道1 void UART1_DMA_Init(void) { stc_dma_cfg_t stcDmaCfg; // 使能DMA时钟 CLK_SetPeriClk(CLK_PERI_DMA, ENABLE); DMA_StructInit(stcDmaCfg); // 内存到外设 stcDmaCfg.u32SrcAddr (uint32_t)uart_send_buf; // 源地址 stcDmaCfg.u32DstAddr (uint32_t)M0P_UART1-DR; // 目的地址 stcDmaCfg.u32SrcInc DMA_SRC_INC_ENABLE; // 源地址自增 stcDmaCfg.u32DstInc DMA_DST_INC_DISABLE; // 目的地址不自增 stcDmaCfg.u32Width DMA_WIDTH_8BIT; // 8位数据 stcDmaCfg.u32Mode DMA_MODE_NORMAL; // 普通模式 stcDmaCfg.u32BurstCnt DMA_BURST_CNT_1; DMA_Init(DMA_CH1, stcDmaCfg); // 使能DMA完成中断 DMA_IntCmd(DMA_CH1, DMA_INT_TC, ENABLE); NVIC_SetPriority(DMA_IRQn, 2); NVIC_EnableIRQ(DMA_IRQn); } // DMA中断服务函数 void DMA_IRQHandler(void) { if(DMA_GetIntFlag(DMA_CH1, DMA_INT_TC)) { DMA_ClearIntFlag(DMA_CH1, DMA_INT_TC); DMA_Cmd(DMA_CH1, DISABLE); dma_tx_done 1; // 发送完成标志 } } // DMA方式发送函数 void UART1_DMA_SendData(uint8_t *buf, uint16_t len) { // 等待上一次发送完成 while(DMA_GetCmdStatus(DMA_CH1) ENABLE); dma_tx_done 0; // 设置传输长度 DMA_SetTransferCnt(DMA_CH1, len); // 设置源地址 DMA_SetSrcAddr(DMA_CH1, (uint32_t)buf); // 使能DMA启动发送 DMA_Cmd(DMA_CH1, ENABLE); }3. 使用方法int main(void) { UART1_Init(); UART1_DMA_Init(); uint8_t test_buf[] Hello HC32L130 UART DMA Mode!\r\n; while(1) { // DMA发送 UART1_DMA_SendData(test_buf, sizeof(test_buf)); while(!dma_tx_done); // 等待发送完成 delay_ms(1000); } }五、性能对比实测关键数据测试条件8MHz 系统时钟波特率 115200发送 256 字节数据表格对比项中断发送方式DMA 发送方式优势方CPU 占用率高逐字节中断极低仅启动 完成DMA发送耗时约 22ms约 22ms相同由波特率决定中断次数256 次1 次DMA系统实时性差频繁打断主程序优无频繁中断DMA功耗较高CPU 频繁唤醒低CPU 可休眠DMA大数据发送易卡顿、丢数据稳定不丢包DMA代码复杂度简单中等中断核心结论发送速度两种方式完全一致速度由波特率决定CPU 占用DMA 方式几乎不占用 CPU适合多任务 / 低功耗场景使用场景少量数据、简单需求 →中断方式大量数据、低功耗、高实时性 →DMA 方式六、关键注意事项HC32L130 UART1 TX 固定对应DMA 通道 1不可修改发送缓冲区必须定义为全局变量DMA 无法访问局部栈变量连续发送时必须等待上一次发送完成避免数据覆盖中断优先级建议DMA UART避免抢占异常。总结提供了可直接编译运行的 HC32L130 串口中断发送和DMA 发送完整代码两种方式发送速度相同DMA 在 CPU 占用、功耗、稳定性上全面领先小数据用中断、大数据 / 低功耗用 DMA是嵌入式 MCU 串口发送的最佳实践。

更多文章