# STM32F103 串口 DMA 发送接收程序 (分头文件和源文件)

下面将程序分为头文件和源文件,并添加详细的文件注释和函数注释。

文件结构

stm32f103_uart_dma/
├── inc/
│   ├── uart_dma.h          // 头文件
├── src/
│   ├── uart_dma.c          // 源文件
│   ├── main.c              // 主程序

1. 头文件 (uart_dma.h)

/**
  ******************************************************************************
  * @file    uart_dma.h
  * @brief   Header for UART DMA communication module
  * @author  Embedded Expert
  * @version V1.0
  * @date    2023-06-01
  ******************************************************************************
  * @attention
  *
  * This module provides UART communication using DMA for STM32F103.
  * Features:
  *   - DMA-based UART transmission and reception
  *   - Circular buffer for reception
  *   - Interrupt handling for transmission completion
  *
  ******************************************************************************
  */

#ifndef __UART_DMA_H
#define __UART_DMA_H

#include "stm32f10x.h"

/* Exported defines ----------------------------------------------------------*/
#define TX_BUFFER_SIZE  32      // 发送缓冲区大小
#define RX_BUFFER_SIZE  256     // 接收缓冲区大小

/* Exported types ------------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
extern uint8_t TxBuffer[TX_BUFFER_SIZE];  // 发送缓冲区
extern uint8_t RxBuffer[RX_BUFFER_SIZE];  // 接收缓冲区

/* Exported functions --------------------------------------------------------*/

/**
  * @brief  初始化UART DMA通信模块
  * @param  None
  * @retval None
  */
void UART_DMA_Init(void);

/**
  * @brief  通过DMA发送数据
  * @param  buffer: 要发送的数据缓冲区
  * @param  length: 要发送的数据长度
  * @retval None
  */
void UART_DMA_Send(uint8_t *buffer, uint16_t length);

/**
  * @brief  获取接收到的数据长度
  * @param  None
  * @retval 已接收的数据长度
  */
uint16_t UART_DMA_GetReceivedLength(void);

/**
  * @brief  处理接收到的数据
  * @param  length: 接收到的数据长度
  * @retval None
  */
void UART_DMA_ProcessReceivedData(uint16_t length);

#endif /* __UART_DMA_H */

2. 源文件 (uart_dma.c)

/**
  ******************************************************************************
  * @file    uart_dma.c
  * @brief   Implementation of UART DMA communication module
  * @author  Embedded Expert
  * @version V1.0
  * @date    2023-06-01
  ******************************************************************************
  * @attention
  *
  * This module implements UART communication using DMA for STM32F103.
  * USART1 is used with DMA1 Channel4 (TX) and Channel5 (RX).
  *
  ******************************************************************************
  */

#include "uart_dma.h"
#include <stdio.h>

/* Private defines -----------------------------------------------------------*/
#define USART1_DR_Base  0x40013804  // USART1数据寄存器基地址

/* Private variables ---------------------------------------------------------*/
uint8_t TxBuffer[TX_BUFFER_SIZE] = "STM32 DMA UART Test\r\n";  // 发送缓冲区
uint8_t RxBuffer[RX_BUFFER_SIZE];                              // 接收缓冲区

/* Private function prototypes -----------------------------------------------*/
static void RCC_Configuration(void);
static void GPIO_Configuration(void);
static void USART_Configuration(void);
static void DMA_Configuration(void);
static void NVIC_Configuration(void);

/**
  * @brief  初始化UART DMA通信模块
  * @param  None
  * @retval None
  */
void UART_DMA_Init(void)
{
    // 系统时钟配置
    RCC_Configuration();
    
    // GPIO配置
    GPIO_Configuration();
    
    // USART配置
    USART_Configuration();
    
    // DMA配置
    DMA_Configuration();
    
    // NVIC配置
    NVIC_Configuration();
}

/**
  * @brief  系统时钟配置
  * @param  None
  * @retval None
  */
static void RCC_Configuration(void)
{
    // 复位时钟配置
    RCC_DeInit();
    
    // 使能外部高速晶振
    RCC_HSEConfig(RCC_HSE_ON);
    
    // 等待HSE就绪
    while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);
    
    // 设置PLL时钟源及倍频系数
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
    
    // 使能PLL
    RCC_PLLCmd(ENABLE);
    
    // 等待PLL就绪
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
    
    // 设置系统时钟为PLL输出
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    
    // 等待系统时钟设置完成
    while(RCC_GetSYSCLKSource() != 0x08);
    
    // 使能DMA时钟
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    
    // 使能USART1和GPIOA时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
}

/**
  * @brief  GPIO配置
  * @param  None
  * @retval None
  */
static void GPIO_Configuration(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    // 配置USART1 Tx (PA9)为复用推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 配置USART1 Rx (PA10)为浮空输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
}

/**
  * @brief  USART配置
  * @param  None
  * @retval None
  */
static void USART_Configuration(void)
{
    USART_InitTypeDef USART_InitStructure;
    
    // USART基本配置
    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART1, &USART_InitStructure);
    
    // 使能USART
    USART_Cmd(USART1, ENABLE);
}

/**
  * @brief  DMA配置
  * @param  None
  * @retval None
  */
static void DMA_Configuration(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    
    // DMA发送配置 (USART1_TX使用DMA1通道4)
    DMA_DeInit(DMA1_Channel4);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)TxBuffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST; // 内存到外设
    DMA_InitStructure.DMA_BufferSize = TX_BUFFER_SIZE;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; // 普通模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel4, &DMA_InitStructure);
    
    // DMA接收配置 (USART1_RX使用DMA1通道5)
    DMA_DeInit(DMA1_Channel5);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)RxBuffer;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 外设到内存
    DMA_InitStructure.DMA_BufferSize = RX_BUFFER_SIZE;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 循环模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel5, &DMA_InitStructure);
    
    // 使能USART DMA发送和接收请求
    USART_DMACmd(USART1, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);
    
    // 使能DMA接收通道
    DMA_Cmd(DMA1_Channel5, ENABLE);
}

/**
  * @brief  NVIC配置
  * @param  None
  * @retval None
  */
static void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    
    // 配置DMA发送完成中断
    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel4_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    // 使能DMA发送完成中断
    DMA_ITConfig(DMA1_Channel4, DMA_IT_TC, ENABLE);
}

/**
  * @brief  通过DMA发送数据
  * @param  buffer: 要发送的数据缓冲区
  * @param  length: 要发送的数据长度
  * @retval None
  */
void UART_DMA_Send(uint8_t *buffer, uint16_t length)
{
    // 等待上一次传输完成
    while(DMA_GetFlagStatus(DMA1_FLAG_TC4) == RESET);
    
    // 清除传输完成标志
    DMA_ClearFlag(DMA1_FLAG_TC4);
    
    // 配置DMA传输数据长度
    DMA_SetCurrDataCounter(DMA1_Channel4, length);
    
    // 重新设置内存地址
    DMA1_Channel4->CMAR = (uint32_t)buffer;
    
    // 使能DMA通道
    DMA_Cmd(DMA1_Channel4, ENABLE);
}

/**
  * @brief  获取接收到的数据长度
  * @param  None
  * @retval 已接收的数据长度
  */
uint16_t UART_DMA_GetReceivedLength(void)
{
    // 计算已接收数据长度 (循环缓冲区)
    return RX_BUFFER_SIZE - DMA_GetCurrDataCounter(DMA1_Channel5);
}

/**
  * @brief  处理接收到的数据
  * @param  length: 接收到的数据长度
  * @retval None
  */
void UART_DMA_ProcessReceivedData(uint16_t length)
{
    // 示例: 回显接收到的数据
    UART_DMA_Send(RxBuffer, length);
    
    // 这里可以添加更复杂的数据处理逻辑
    // 例如协议解析、数据存储等
}

/**
  * @brief  DMA1通道4中断服务函数 (发送完成中断)
  * @param  None
  * @retval None
  */
void DMA1_Channel4_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA1_IT_TC4) != RESET)
    {
        // 清除中断标志
        DMA_ClearITPendingBit(DMA1_IT_TC4);
        
        // 可以在这里添加发送完成后的处理代码
        // 例如: 点亮LED表示发送完成
    }
}

3. 主程序 (main.c)

/**
  ******************************************************************************
  * @file    main.c
  * @brief   Main program body
  * @author  Embedded Expert
  * @version V1.0
  * @date    2023-06-01
  ******************************************************************************
  * @attention
  *
  * Main application for UART DMA communication demo.
  *
  ******************************************************************************
  */

#include "uart_dma.h"
#include "stm32f10x.h"

/**
  * @brief  Main program
  * @param  None
  * @retval None
  */
int main(void)
{
    // 初始化UART DMA模块
    UART_DMA_Init();
    
    // 发送初始测试数据
    UART_DMA_Send(TxBuffer, sizeof(TxBuffer));
    
    while(1)
    {
        // 获取接收数据长度
        uint16_t receivedLength = UART_DMA_GetReceivedLength();
        
        // 如果有数据接收
        if(receivedLength > 0)
        {
            // 处理接收到的数据
            UART_DMA_ProcessReceivedData(receivedLength);
        }
        
        // 可以添加其他应用代码
    }
}

/************************ (C) COPYRIGHT Embedded Expert *****END OF FILE****/

程序说明

  1. 模块化设计

    • 将UART DMA功能封装为独立模块
    • 清晰的接口设计,便于其他模块调用
    • 内部实现细节对外隐藏
  2. 完整注释

    • 每个文件头部有详细说明
    • 每个函数有功能描述和参数说明
    • 关键代码行有注释说明
  3. 功能特点

    • 使用DMA实现高效UART通信
    • 发送使用普通模式,接收使用循环缓冲区
    • 提供发送完成中断通知
    • 示例实现了简单的数据回显功能
  4. 使用方法

    • 调用UART_DMA_Init()初始化模块
    • 使用UART_DMA_Send()发送数据
    • 在主循环中检查接收数据长度并处理

这个分文件实现的版本更加规范,适合实际项目开发,便于维护和扩展。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

章鱼哥嵌入式开发

坚持不易,你们的鼓励是我的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值