STM32使用DMA接收串口数据

2023-05-16

目录

01、概述

02、DMA接收

03、中断

04、代码


01、概述

在之前的文章里《STM32串口详解》和《STM32 DMA详解》文章中,详细讲解了STM32的串口和DMA外设,本篇文章将不在细述串口和DMA的知识。

在串口讲解的文章中,示例代码采用中断方式接收和发送数据,中断的好处在于可以及时响应,快速接收到数据,但缺点也很明显,那就是频繁中断,接收1000个字节需要中断1000次,频繁中断就意味着会打断其他代码的执行,对一些应用场景是不允许的。这个时候,使用DMA+串口的组合就可以很好解决这个问题。

图片

DMA每个数据流有8个通道,每个通道映射到不同外设,这有利于针对不同的产品配置不同的DMA外设请求。

每个数据流只能配置为映射到一个通道,无法配置为映射到多个通道。即,与数据流不同,每个DMA控制器可以同时配置多个数据流(因为有仲裁器),但每个数据流不能同时配置多个通道(因为只有选择器)。

我们使用USART1串口外设,从数据手册中可以查到,USART1的发送和接收都是支持DMA的,使用的是DMA2.

图片

接下来我们循序渐进了解DMA在串口中的应用

02、DMA接收

我们先配置DMA,将DMA外设和串口联动起来。首先需要配置DMA。

DMA配置这一块不再详解,不太懂的同学请看文章《STM32DMA详解》,这里我们直接贴代码。

void DMA_Config(void)
{
  DMA_InitTypeDef  DMA_InitStructure;
    
  /* Enable DMA clock */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
  
  /* Reset DMA Stream registers (for debug purpose) */
  DMA_DeInit(DMA2_Stream2);

  /* Check if the DMA Stream is disabled before enabling it.
     Note that this step is useful when the same Stream is used multiple times:
     enabled, then disabled then re-enabled... In this case, the DMA Stream disable
     will be effective only at the end of the ongoing data transfer and it will 
     not be possible to re-configure it before making sure that the Enable bit 
     has been cleared by hardware. If the Stream is used only once, this step might 
     be bypassed. */
  while (DMA_GetCmdStatus(DMA2_Stream2) != DISABLE)
  {
  }
  
  /* Configure DMA Stream */
  DMA_InitStructure.DMA_Channel = DMA_Channel_4;  //DMA请求发出通道
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;//配置外设地址
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)UART_Buffer;//配置存储器地址
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//传输方向配置
  DMA_InitStructure.DMA_BufferSize = (uint32_t)32;//传输大小
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址不变
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;//memory地址自增
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;//外设地址数据单位
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;//memory地址数据单位
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//DMA模式:正常模式
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;//优先级:高
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;//FIFO 模式不使能.          
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;// FIFO 阈值选择
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发模式选择,可选单次模式、 4 节拍的增量突发模式、 8 节拍的增量突发模式或 16 节拍的增量突发模式。
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发模式选择,可选单次模式、 4 节拍的增量突发模式、 8 节拍的增量突发模式或 16 节拍的增量突发模式。
  DMA_Init(DMA2_Stream2, &DMA_InitStructure); 
  
  /* DMA Stream enable */
  DMA_Cmd(DMA2_Stream2, ENABLE);
}

除了配置DMA外设外,我们还需要配置串口对应的DMA配置,在手册有一小章节讲解到。

图片

需要配置的寄存器是USART_CR3寄存器。

图片

我们可以通过配置USART_CR3寄存器的bit6和bit7使能串口发送和接收DMA。ST的标准外设库同样提供了对应的外设库。

void USART_DMACmd(USART_TypeDef* USARTx, uint16_t USART_DMAReq, FunctionalState NewState)

通过上面接口可以配置串口的DMA配置如下:

/*使能串口DMA接收*/
USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);

03、中断

我们使用DMA+串口解决了频繁中断的问题,但现在有一个问题,我们还需要及时将接收的数据信息通知CPU,以便达到数据的及时性。我们使用DMA和串口两个外设,他们都有自己的中断。

使用DMA中断,如下配置

/* Enable DMA Stream Transfer Complete interrupt */
DMA_ITConfig(DMA2_Stream2, DMA_IT_TC, ENABLE);
  
/* Enable the DMA Stream IRQ Channel */
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

当DMA接收完毕时,会产生中断通知CPU取数据。

但这有个明显的缺陷:串口接收一包数据,长度如果小于DMA的缓冲长度,那么久不能触发中断,只能等DMA接收满数据才会产生中断,如果下一包数据迟迟不来,那么这一包就不能被及时响应。

那么我们采用串口中断是一个不错的方案。串口提供了一个空闲中断,“似乎”就是为了DMA专门使用的。

图片

当串口接收一包数据,接收完最后一个字节,没有数据接收时,会产生一个中断,这个时候,CPU就可以取数据。

串口的配置知识不再讲解,不太懂的同学请看《STM32串口详解》,串口空闲中断配置如下

USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);
  
/* Enable the USARTx Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

串口中断代码如下

void USART1_IRQHandler(void)
{
  uint8_t temp;
  if(USART_GetFlagStatus(USART1, USART_FLAG_IDLE) == SET)
  {
    DealWith_UartData();
//    USART_ClearFlag(USART1, USART_FLAG_IDLE);
    temp = USART1->SR;  
    temp = USART1->DR; //清USART_IT_IDLE标志  
  }
}

重点:这里有一个坑!!!

清除空闲中断位的代码是

temp = USART1->SR;   
temp = USART1->DR; //清USART_IT_IDLE标志

证据如下

图片

这一点很坑人,注意。

04、代码

DMA+串口接收的工程代码是开源的,Keil和IAR的工程都有

图片

33-USART-DMA-Receive         DMA串口接收(没有使用中断)

34-USART-Receive-DMAInterrupt DMA串口接收(DMA中断)

35-USART-DMA-Receive-Interrupt DMA串口接收(串口空闲中断)

PCB和工程代码开源地址:

https://github.com/strongercjd/STM32F207VCT6

点击查看本文所在的专辑,STM32F207教程

关注公众号,第一时间收到文章更新

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32使用DMA接收串口数据 的相关文章

  • STM32 F072上的软件如何跳转到bootloader(DFU模式)?

    STM32应用笔记2606对此进行了讨论 但没有简单的代码示例 该答案已使用 IAR EWARM 在 STM32F072 Nucleo 板上进行了测试 这个答案使用 STM32标准外设库 仅此而已 请注意 验证您是否成功进入引导加载程序模式
  • 136-基于stm32单片机家庭温湿度防漏水系统设计Proteus仿真+源程序

    资料编号 136 一 功能介绍 1 采用stm32单片机 LCD1602显示屏 独立按键 DHT11传感器 蜂鸣器 制作一个基于stm32单片机家庭温湿度防漏水系统设计Proteus仿真 2 通过DHT11传感器检测当前温湿度 并且显示到L
  • HAL库STM32常用外设教程(二)—— GPIO输入\输出

    HAL库STM32常用外设教程 二 GPIO输入 输出 文章目录 HAL库STM32常用外设教程 二 GPIO输入 输出 前言 一 GPIO功能概述 二 GPIO的HAl库驱动 三 GPIO使用示例 1 示例功能 四 代码讲解 五 总结
  • Push_back() 导致程序在进入 main() 之前停止

    我正在为我的 STM32F3 Discovery 板使用 C 进行开发 并使用 std deque 作为队列 在尝试调试我的代码 直接在带有 ST link 的设备上或在模拟器中 后 代码最终在 main 中输入我的代码之前在断点处停止 然
  • [屏驱相关]【SWM166-SPI-Y1.28C1测评】+ 有点惊艳的开箱

    耳闻华芯微特许久了 看到论坛得评测活动赶紧上了末班车 毕竟对有屏幕得板子也是很喜欢得 京东快递小哥客客气气 微笑着把快递给了我 好评 直接拆了包 在此之前没看过视频号 所以这个圆盘盘得模具还是有点惊喜的 正面照如下 开机有灯光秀 还有动画
  • SHT10温湿度传感器——STM32驱动

    实验效果 硬件外观 接线 3 3V供电 IIC通讯 代码获取 查看下方 END
  • HAL 锁定和解锁函数如何使用以及为什么?

    我试图理解另一位程序员编写的代码 它使用了I C http en wikipedia org wiki I C2 B2C通信以将数据写入 STM32 微控制器的 EEPROM 一般来说 我理解他的代码是如何工作的 但我不明白他为什么使用HA
  • 解决KEIL编译慢问题

    两种方案 使用v6版本的ARM Compiler 如果v6版本编译不过 必须使用v5版本的 则可以勾选掉Browse Information选项 提升很明显 1分多钟能优化到几秒 看代码量 但是这个有个弊端 在KEIL中会影响函数跳转 建议
  • 最终启动顺序错误 - STM32L476 的 Eclipse System Workbench 调试

    我正在尝试调试和运行 STM32L476 的简单汇编代码 我已经设置了 Eclipse Oxygen 在 Eclipse 中安装了最新版本的 System Workbench 插件并安装了 ST Link 驱动程序 IDE 成功构建了程序
  • 串口通讯第一次发送数据多了一字节

    先初始化IO再初始化串口 导致第一次发送时 多出一个字节数据 优化方案 先初始化串口再初始化IO 即可正常通讯
  • DMA 与中断驱动的 I/O

    我不太清楚 DMA 和中断 I O 之间的区别 当前正在阅读操作系统概念 第 7 版 具体来说 我不确定在这两种情况下何时会发生中断 以及在这两种情况下 CPU 在什么时候可以自由地执行其他工作 我一直在读但不一定能调和的东西 中断驱动 通
  • STM32F4XX的12位ADC采集数值超过4096&右对齐模式设置失败

    文章目录 一 前言 二 问题1 数值超过4096 三 问题1的排错过程 四 问题2 右对齐模式设置失败 五 问题2的解决方法 5 1 将ADC ExternalTrigConv设置为0 5 2 使用ADC StructInit 函数 一 前
  • STM32H5 Nucleo-144 board开箱

    文章目录 开发板资料下载 目标 点亮LD1 绿 LD2 黄 和LD3 红 三个LED灯 开箱过程 博主使用的是STM32CubeMX配置生成代码 具体操作如下 打开STM32CubeMX File gt New project 选择开发板型
  • Cortex-M3与M4权威指南

    处理器类型 所有的ARM Cortex M 处理器是32位的精简指令集处理器 它们有 32位寄存器 32位内部数据路径 32位总线接口 除了32位数据 Cortex M处理器也可以有效地处理器8位和16位数据以及支持许多涉及64位数据的操作
  • Linux内核设备驱动程序以DMA方式进入内核空间

    LDD3 p 453 演示dma map single使用作为参数传入的缓冲区 bus addr dma map single dev gt pci dev gt dev buffer count dev gt dma dir Q1 这个缓
  • PWM DMA 到整个 GPIO

    我有一个 STM32F4 我想对一个已与掩码进行 或 运算的 GPIO 端口进行 PWM 处理 所以 也许我们想要 PWM0b00100010一段时间为 200khz 但随后 10khz 后 我们现在想要 PWM0b00010001 然后
  • 在 Contiki 程序中使用 malloc

    考虑以下 Contiki 程序 include
  • HAL_Delay() 陷入无限循环

    我被 HAL Delay 函数困住了 当我调用此函数 HAL Delay 时 控制陷入无限循环 在寻找问题的过程中 我发现了这个 http www openstm32 org forumthread2145 threadId2146 htt
  • 哪些变量类型/大小在 STM32 微控制器上是原子的?

    以下是 STM32 微控制器上的数据类型 http www keil com support man docs armcc armcc chr1359125009502 htm http www keil com support man d
  • 移动数组中的元素

    我需要一点帮助 我想将数组中的元素向上移动一个元素 以便新位置 1 包含位置 1 中的旧值 new 2 包含 old 1 依此类推 旧的最后一个值被丢弃 第一个位置的新值是我每秒给出的新值 我使用大小为 10 的数组 uint32 t TE

随机推荐

  • Java操作数据库方式(六)DataSource详解

    概述 在java世界里操作数据库有很多方式 xff0c 在众多方式中除了JDBC外都有DataSource对象 DataSource可以看作数据源 xff0c 它封装了数据库参数 xff0c 连接数据库 xff0c 程序中操作DataSou
  • MySql(四)之项目实战

    概述 MySql项目实战是结合实际开发工作 xff0c 来说明数据库分析 xff0c 数据库设计 xff0c 数据库创建等一些列流程 这部分知识不属于严谨的技术 xff0c 不同的人有不同的方法 xff0c 如果你不认可你可以继续自己的方法
  • MySql(五)之sql优化

    概述 作为一个高级程序员 xff0c 不仅要熟练使用sql语句 xff0c 更应该使用高效的sql语句 本篇blog讲解的内容主要包括 xff1a 索引的使用 执行计划分析 sql优化常见案例分析 索引 一 xff0c 什么是索引 索引的作
  • Oracle(一)之安装与使用

    概述 oracle是关系型数据库中的一种 xff0c 与MySql类似 xff0c 也是一种数据库服务 xff0c oracle公司出品 比MySql安全可靠 xff0c 但收费 oracle数据库无论在存储数据量 xff0c 性能 xff
  • Oracle(二)之视图的使用

    概述 什么是视图 视图可以理解为一张虚拟表 xff0c 它是由固定的sql查询语句操作真实表得到的一个临时表 视图中的数据就是查询sql语句的结果 得到视图之后 xff0c 我们可以使用sql操作视图 xff0c 但只能是查询操作 查询视图
  • CMUX 软件包发布 | 不一样的串口复用

    1 什么是 CMUX CMUX xff08 Connection Multiplexing xff09 xff0c 即连接 xff08 串口 xff09 多路复用 xff0c 其功能主要在一个真实的物理通道上虚拟多个通道 xff0c 每个虚
  • Linux中使用curl命令发送带参数的get请求和post请求

    1 curl与wget 命令的区别 相似之处 xff1a wget 和 cURL 都可以下载内容 xff0c 都可以向互联网发送请求并返回请求项 xff0c 也可以进行 HTTP POST 请求 xff0c 它们都是命令行工具 xff0c
  • STM32片上Flash内存映射、页面大小、寄存器映射

    本文以STM32F103RBT6为例介绍了片上Flash Embedded Flash 若干问题 xff0c 包括Flash大小 内存映射 块大小 页面大小 寄存器 二 块大小 Flash先分块再分页 xff0c 擦除是按块进行 xff0c
  • keil 修改RAM、ROM

  • 单片机flash不足,keil如下方式进行优化

    单片机的flash不够的时候可以使用keil的优化等级进行优化 xff1b 但是使用Opt进行优化的时候会遇到难以预料的错误 xff0c 所以使用时要对一些变量进行标识 xff0c 比如使用volatile关键字 还有其他方式也能减少内存的
  • msp430看门狗定时器

    看门狗定时器用来防止程序因供电电源 空间电磁干扰或其它原因引起的强烈干扰噪声而跑飞的事故 在很多单片机中都内置了看门狗 xff0c 看门狗本身是一个定时器 xff0c 当定时器溢出时即进行系统复位 xff0c 因此需要在程序中对看门狗定时器
  • UART、SPI和IIC详解与比较(超级实用的调试经验)

    1 UART UART有4个pin xff08 VCC GND RX TX xff09 用的TTL电平 低电平为0 0V xff0c 高电平为1 xff08 3 3V或以上 xff09 UART使用的是异步串行通信 UART是两线 xff0
  • RS232、RS485和CAN协议总结与对比

    一 RS232串口是计算机上一种非常通用的设备通信协议 串口的电气特性 xff1a 1 RS 232串口通信最远距离是50英尺 xff1b 2 RS232可做到双向传输 xff0c 全双工通讯 xff0c 最高传输速率20kbps xff1
  • STM32 GPIOx_CRL/GPIOx_CRH 寄存器

    GPIOx CRL GPIOx CRH xff08 x xff1a A F xff09 寄存器用来对GPIO进行端口设置 xff0c 如 xff1a 设置GPIO为输入模式或输出模式 每个寄存器含有32位 xff0c 每4位用来设置1个GP
  • SHT10 温湿度传感器的程序以及调试总结

    没有其他东西 直接上调试注意事项和代码 xff01 xff01 调试要点 xff1a 1 DATA加10K上拉电阻 2 注意示波器观察各个信号 基础要点 xff1a 1 串行时钟输入 xff08 SCK xff09 单片机模拟时钟 2 串行
  • 晶振原理解析

    目录 01 压电效应 02 晶体振荡器的应用 03 无源晶振和有源晶振的区别 04 STM32外接晶振 下文将进一步讲解晶振的原理 xff0c 以及晶振和STM32的关系 01 压电效应 压电效应 xff1a 某些电介质在沿一定方向上受到外
  • 字符串大小的比较

    字符串大小比较的步骤 xff1a 从左至右一位一位比较 xff0c 如果相同 xff0c 则继续下一位 xff0c 如果不同 xff0c 则谁的ASCII大谁的字符串就大如果比较到其中一者已经结束了 xff0c 还没有分出大小 xff0c
  • STM32延时函数的四种方法

    目录 1 普通延时 2 定时器中断 3 查询定时器 4 汇编指令 单片机编程过程中经常用到延时函数 xff0c 最常用的莫过于微秒级延时delay us 和毫秒级delay ms 本文基于STM32F207介绍4种不同方式实现的延时函数 1
  • STM32的FSMC外设简介

    目录 01 FSMC特点 02 AHB接口 03 外部设备地址映射 04 NOR PSRAM控制器 05 外部存储器接口信号 06 NOR PSRAM控制器异步事务 07 模式1 08 模式A 09 代码说明 01 FSMC特点 Flexi
  • STM32使用DMA接收串口数据

    目录 01 概述 02 DMA接收 03 中断 04 代码 01 概述 在之前的文章里 STM32串口详解 和 STM32 DMA详解 文章中 xff0c 详细讲解了STM32的串口和DMA外设 xff0c 本篇文章将不在细述串口和DMA的