目录

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 disablewill 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教程

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

STM32使用DMA接收串口数据相关推荐

  1. STM32使用DMA发送串口数据

    1.概述 上一篇文章<STM32使用DMA接收串口数据>讲解了如何使用DMA接收数据,使用DMA外设和串口外设,使用的中断是串口空闲中断.本篇文章主要讲解使用DMA发送数据,不会讲解基础的 ...

  2. STM32 UART DMA实现未知数据长度接收(转自amoBBs)

    串口通信是经常使用到的功能,在STM32中UART具有DMA功能,并且收发都可以使用DMA,使用DMA发送基本上大家不会遇到什么问题,因为发送的时候会告知DMA发送的数据长度,DMA按照发送的长度直接 ...

  3. serialport接收串口数据_C#串口操作类,包括串口读写操作

    串口进行操作的类,其中包括写和读操作,类可设置串口参数.设置接收函数.打开串口资源.关闭串口资源,操作完成后,一定要关闭串口.接收串口数据事件.接收数据出错事件.获取当前全部串口.把字节型转换成十六进 ...

  4. java swing 串口_ComTest 接收串口数据,并显示在文本框内,通过JavaSwing实现 Develop 265万源代码下载- www.pudn.com...

    文件名称: ComTest下载  收藏√  [ 5  4  3  2  1 ] 开发工具: Java 文件大小: 3157 KB 上传时间: 2016-09-21 下载次数: 0 提 供 者: 韩坤 ...

  5. 串口通信——接收串口数据并处理(C语言)

    本文主要内容包含:  1.接收串口数据程序的编程逻辑示意图:  2.接收串口数据程序要用到的通用函数模块(可直接引用,无需更改):  3.接收串口数据程序的示例. 1.接收串口数据程序的编程逻辑示意图 ...

  6. 使用iocomp中iplot控件实现接收串口数据并显示曲线

    概述:Iocomp 是一个强大的工业控件.适用于vb/vc/vs.net/Delphi/BCB(windows/linux).囊括了常见的工业控件. 本例使用简单iocomp控件中的一个简单iplot ...

  7. 51UWB单片机连接ESP8266实现Wifi接收串口数据

    UWB定位需要电脑读取UWB基站的串口数据来读取距离信息,用wifi连接可以实现远程接收串口数据方便连接.这里记录一下如何让51UWB单片机接入WiFi模块ESP8266. 前置条件: 单片机完成基站 ...

  8. QT多线程接收串口数据

    ** QT多线程接收串口数据 ** 1.前言 QT多线程的使用,和绝大数人一样,犯了错误(请查阅Qt开发人员( Bradley T. Hughes)Blog中的文章 you are-doing-it- ...

  9. simulink接收串口数据_基于Unity串口通信的解决方案

    思路有三种,等下我会详细介绍. 后面的博客详细介绍是我收录两年前写的博客,现在我已经没有往串口方向进行开发了,所以只能将一些思路分享给大家. ​ ​ 解决方式一:将Unity串口通信数据模块(接收与发 ...

最新文章

  1. oracle中spool卸数,Oracle中如何快速的卸载和加载数据?
  2. stm32跑python-STM32F4系列使用MicroPython开发
  3. 005 定位控件输入call
  4. _Linux系统编程—信号集操作函数
  5. Centos 7 mysql Buffered warning: Changed limits: max_connections: 214 解决方法
  6. 结合源码看nginx-1.4.0之nginx内存管理详解
  7. dedeCMS 会员:个人空间模板style修改
  8. 【人脸识别】FaceNet详解
  9. pythonseleniumide使用_selenium第二课(脚本录制seleniumIDE的使用)
  10. JQuery基础学习笔记(1)
  11. [转]国外英语教学网页
  12. 域控下发脚本_让系统及时的通过域用户脚本自动的打补丁
  13. nginx中upstream的max_conns属性使用
  14. 【Qt-Camera】大华相机显示线程
  15. 多省市房屋交易平台引入电子签章推动住房交易合同网签备案
  16. ThreadLocal的使用场景及使用方式
  17. 中国大学mooc慕课python答案_中国大学MOOC(慕课)Python编程基础答案
  18. CrossAir CA-S01 SMD贴片天线使用步骤
  19. 数字图像处理:图像几何变换(Matlab实现几何变换+原理解析
  20. 如何在CTEX上对论文进行排版

热门文章

  1. tiny服务器系列,项目:TinyHTTP服务器
  2. python是最好的语言 永远二十岁_“Python才是世界上最好的语言”
  3. html显示日志_如何实现类似“jenkins”的滚动日志功能?
  4. linux接收网络数据并存存储,Linux网络设备驱动之数据接收流程(六)
  5. pytorch封装Dataset——封装一般的DataLoader与可迭代的DataLoader(pytorch Data学习五)
  6. spring bean生命周期_Spring中bean的生命周期和扩展点有哪些?
  7. python未来人工智能主流_python深度学习,未来人工智能三大境界的划分
  8. java的vector是什么类_java中vector类
  9. Linux如何安装iperf软件,Linux 下网络性能测试工具 iperf 的安装和使用
  10. 今天闲着没事弄个几个表情包