STM32中usart使用DMA接受数据

在STM32微控制器中,USART(通用同步异步接收发射器)配合DMA(直接存储器访问)用于接收数据,可以大幅提升数据处理的效率,尤其是在接收大量数据时。通过利用DMA,CPU可以从数据传输过程中解放出来,专注于其他任务。以下是配置USART使用DMA接收数据的步骤:

1. 配置USART

首先,需要对USART进行基本配置,这包括设置波特率、数据位、停止位、奇偶校验等。必须确保USART的接收功能被使能。

2. 配置DMA

选择一个合适的DMA通道与USART接收请求相关联,并对该通道进行配置:

  • 设置DMA传输方向:由外设到内存。
  • 设置外设地址:USART数据寄存器的地址。
  • 设置内存地址:指向用于存储接收到的数据的缓冲区的指针。
  • 设置数据传输量:指定DMA传输的数据量,或者选择循环模式,DMA在达到指定数据量后会自动重新开始。
  • 设置外设和内存的数据宽度:通常为 8 位或 16 位,根据USART配置而定。
  • 配置增量模式:通常配置外设地址固定,内存地址增量

3. 使能DMA接收请求

在USART配置中,需要确保使能了DMA接收请求。这通常涉及到设置USART的相关CR(控制寄存器)中的位。

4. 配置DMA中断(可选)

可以配置DMA以在传输完成时产生中断,从而允许软件立即处理接收到的数据。这包括使能DMA通道的传输完成中断,并在NVIC中配置DMA中断。

  1. 启动DMA传

最后,启动DMA传输。这通常通过设置DMA通道的相应控制寄存器启动。

以下是一个配置示例(以串口1 USART1 和 DMA通道 5 为例,具体寄存器请根据实际情况和微控制器参考手册调整)

cpp 复制代码
// USART1 初始化(示例,需要根据实际情况调整)
USART_InitTypeDef USART_InitStruct;
USART_StructInit(&USART_InitStruct);
USART_InitStruct.USART_BaudRate = 9600; // 设置波特率
// 其他配置...
USART_Init(USART1, &USART_InitStruct);
USART_Cmd(USART1, ENABLE);
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE); // 使能USART1的DMA接收请求

// DMA 初始化(以DMA1_Channel5为例)
DMA_InitTypeDef DMA_InitStruct;
DMA_DeInit(DMA1_Channel5);
DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;
DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)buffer; // buffer 是数据存储区
DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStruct.DMA_BufferSize = sizeof(buffer)/sizeof(buffer[0]);
// 其他配置...
DMA_Init(DMA1_Channel5, &DMA_InitStruct);
DMA_Cmd(DMA1_Channel5, ENABLE); // 启动DMA

// 如有必要,配置中断...

如何配置DMA以在传输完成时产生中断?

要配置DMA在传输完成时产生中断,你需要执行以下步骤(假设使用STM32标准库):

1. 配置DMA通道

首先,初始化DMA通道并在初始化结构体中选择合适的参数,包括源和目的地址、数据传输方向、缓冲区大小等。

cpp 复制代码
DMA_InitTypeDef DMA_InitStructure;

// 假设为DMA1的Channel1(以STM32F1系列为例)
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(USART1->DR);
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)buffer; // buffer是数据接收的目的缓冲区
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize = bufferSize;
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_Mode_Circular,视情况而定
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(DMA1_Channel1, &DMA_InitStructure);

2. 使能DMA传输完成中断

在DMA通道初始化之后,使能特定的DMA中断。这通常意味着传输完成中断(TC,Transfer Complete)。

cpp 复制代码
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);

3. 配置NVIC来使能DMA中断

接着,需要配置嵌套向量中断控制器(NVIC),以使能并设置DMA中断的优先级。

cpp 复制代码
NVIC_InitTypeDef NVIC_InitStructure;

// 为了使用DMA1_Channel1中断
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01; // 预抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01; // 响应优先级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

4. 实现DMA中断处理程序

在中断处理程序中,你需要检查传输完成标志,并且可能要清除该标志。此外,你可以在这一点上处理数据或者再次启动DMA传输。

cpp 复制代码
void DMA1_Channel1_IRQHandler(void)
{
    // 检查是否DMA1_Channel1传输完成
    if(DMA_GetITStatus(DMA1_IT_TC1))
    {
        DMA_ClearITPendingBit(DMA1_IT_TC1); // 清除中断标志位

        // 传输完成,处理数据
    }
}
  • 对于循环传输模式(DMA_Mode_Circular),请注意处理数据的速度要跟得上DMA传输的速度,避免数据丢失。
  • 中断处理程序名(例如DMA1_Channel1_IRQHandler)是固定的,根据DMA通道而决定,参考相应的微控制器参考手册确定准确的名称。
相关推荐
代码游侠8 小时前
学习笔记——设备树基础
linux·运维·开发语言·单片机·算法
xuxg200510 小时前
4G 模组 AT 命令解析框架课程正式发布
stm32·嵌入式·at命令解析框架
CODECOLLECT12 小时前
京元 I62D Windows PDA 技术拆解:Windows 10 IoT 兼容 + 硬解码模块,如何降低工业软件迁移成本?
stm32·单片机·嵌入式硬件
BackCatK Chen12 小时前
STM32+FreeRTOS:嵌入式开发的黄金搭档,未来十年就靠它了!
stm32·单片机·嵌入式硬件·freertos·低功耗·rtdbs·工业控制
全栈游侠15 小时前
STM32F103XX 02-电源与备份寄存器
stm32·单片机·嵌入式硬件
Lsir10110_15 小时前
【Linux】中断 —— 操作系统的运行基石
linux·运维·嵌入式硬件
深圳市九鼎创展科技17 小时前
瑞芯微 RK3399 开发板 X3399 评测:高性能 ARM 平台的多面手
linux·arm开发·人工智能·单片机·嵌入式硬件·边缘计算
Industio_触觉智能17 小时前
触觉智能RV1126B核心板配置USB复合设备(下)
串口·acm·开发板·usb·rv1126b·ums·usb存储
辰哥单片机设计17 小时前
STM32项目分享:车辆防盗报警系统
stm32·单片机·嵌入式硬件
風清掦19 小时前
【江科大STM32学习笔记-05】EXTI外部中断11
笔记·stm32·学习