STM32F0x HAL库学习笔记(7)DMA数据的传输配置:串口数据的DMA发送与接收

2023-10-29

本文开发环境:

  • MCU型号:STM32F051R8T6
  • IDE环境: MDK 5.25
  • 代码生成工具:STM32CubeMx 5.0.1
  • HAL库版本:v1.9.0(STM32Cube MCU Package for STM32F0 Series)

本文内容:

  1. DMA 内存到内存的数据传输
  2. DMA 内存到串口的数据传输
  3. DMA 串口数据到内存的传输


1. DMA 简介

DMA(直接存储器访问)提供了数据传输功能,如果我们不需要对数据进行处理,只需要原封不动的从一个地址搬移到另一个地址,那么DMA是一个不错的选择,特别在数据量很大的情况,可以大大的减轻内核的负担,再程序实现之前,建议了解一下DMA的基本原理和事件,以便更好的理解配置的过程。关于与DMA数据手册和网上已经有了非常多资源介绍,这里不再赘述。

2. DMA数据内存到内存的搬运

2.1 CubeMx 配置

内存到内存的配置比较简单,我们只需要指定使用哪个DMA通道即可,接着我们再到程序中指定具体的源内存地址和目标内存地址,即可实现DMA的数据搬运功能,首先添加一个DMA通道,具体如下所示:
在这里插入图片描述
当我们添加完了以后,就可以开始配置DMA参数,我们依次配置,如下所示:
在这里插入图片描述
设置里面有一个Mode,这里只能选择Normal模式,表示每启动一次搬运,则搬运一次后停止,而不是一直不断的搬运。Increment Address 表示搬运数据过程中内存地址是否增长,比如你想要源数组原封不动的搬运到目标数组,那么就需要源地址和目标地址都勾选地址增长,如果你需要把第源数组的第一个值,赋值给目标数组里面所有的元素,则不勾选源地址的地址增长,且勾选目标地址的增长。数据宽度我们都选择Byte,即使选择一字节长度来搬运数据。

2.2 Example

当我们配置好这些以后,就可以生成代码了(当然这建立在你工程的时钟模块等基本配置已经设置好的情况),如果你不清楚STM32CubeMx如何新建一个工程,可以参考一个简单的IO工程配置。接着我们可以使用以下函数来调用一次DMA数据传输:

while (1)
{
    /* USER CODE END WHILE */
		uint8_t scr_data[20] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
  	    uint8_t dst_data[20] = {0};
		HAL_Delay(50);
		
		HAL_DMA_Start(&hdma_memtomem_dma1_channel1, (uint32_t)&scr_data, (uint32_t)&dst_data,20);
		HAL_DMA_PollForTransfer(&hdma_memtomem_dma1_channel1,HAL_DMA_FULL_TRANSFER,20);
}

当我们运行这段程序后,在HAL_DMA_PollForTransfer()之后打印出dst_data[]数组的值,可以发现和scr_data[]的值一模一样,这证明我本次DMA搬运是成功的。你可以通过硬件调试直接查看数组的值。

这里简单解释一下HAL_DMA_Start()函数和HAL_DMA_PollForTransfert()函数:

2.2.1 HAL_DMA_Start() 函数

HAL_DMA_Start()函数开启了一次DMA传输,从 scr_data 向 dst_data 搬运数据,总共20个字节。当开启这是传输后,DMA将被标记为忙状态,CPU将运行以后的程序。

2.2.2 HAL_DMA_PollForTransfer() 函数

需要注意的是,由于我们CPU没必要也不应该去等DMA传输完成后再运行程序,所以当我们要开始一次新的传输之前,我们需要判断上次开启的DMA是不是已经传输完成了,这时候我们使用 HAL_DMA_PollForTransfer()来查看,第二个参数表示传输的完整度,可以选择Full或者是Half,我们这里选择了Full,只有传输完所有数据了,才认为是传输完成。这部分设计到了DMA传输事件的相关内容。这个函数如果检测到DMA完成了,还会把DMA的状态设置会待续。所以如果我们忘记使用这个函数,就会发现我们的HAL_DMA_Start()只能调用一次,此后每一次,都会返回DMA忙碌的错误状态。

3. 内存到外设的传输

我们可以把数据从内存传输到内存,也可以把数据传输到外设,当然也可以把外设的数据传到了内存。这里以内存到外设为例,把数组的值传到串口发送寄存器中,实现数据自动发送。

3.1 CubeMx 配置

如果我们没有配置串口,会发现添加DMA的时候,没有串口相关的DMA配置供我们选择,所以首先添配置串口(如果你已经配置好了,这一步就可以跳过):
在这里插入图片描述
以上是串口配置基本配置,前文以后介绍,不在赘述,接着我们需要配置DMA相关的参数:
在这里插入图片描述
Mode我们选择Normal,即发送一次既可,如果选择Circular,则会一直循环发送。由于我们是把数据发送到串口发送寄存器,所以目标地址不能增长。最后还需要勾选串口的全局中断使能,否则DMA传送只能发送一次(注1),具体操作如下:
在这里插入图片描述

3.2 Example

我们使用HAL_UART_Transmit_DMA()发送函数来开启一次串口的DMA传送,具体代码如下:

... ...
  uint8_t tx_str[] = "Welcome to Yonas's Blog!\r\n";
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		HAL_UART_Transmit_DMA(&huart1,tx_str,sizeof(tx_str));
		HAL_Delay(500);
... ...
  }

我们定义了tx_str[]字符串,然后就可以使用HAL_UART_Transmit_DMA()函数发送这个字符串了,这里直接只用用sizeof()来计算大小,这样以便我们随意修改字符串数组。
当我们运行以上代码时候,就可以发现程序以500ms的速度向串口打印数据:
在这里插入图片描述

3. 外设到内存的传输

3.1 串口中 DMA 的配置

在这个示例中,选择DMA的模式为Circular模式,这是为了每一次串口中断,都可以发生搬运。
在这里插入图片描述

3.2 NVIC 中 DMA 的配置

需要开启串口中断和DMA中断,并且勾选生成代码,具体擦做如下:
在这里插入图片描述
接着还需要配置 Code generation ,具体操作如下:
在这里插入图片描述

3.3 Example

当我们配置好DMA后,就可以进行DMA传送了,以下是一个示例,它们被写在了main.c中:

... ...
uint8_t rx_buf[1];                             //接收串口数据存放的数组
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
		HAL_UART_Transmit(&huart1,rx_buf,sizeof(rx_buf),200);
}
... ...
void main(void)
{
	... ..
	HAL_UART_Receive_DMA(&huart1,rx_buf,1);                 //设置DMA接收到的数据存放在rx_buf中
	while(1)
	{
		... ...
	}
}

以上程序示例了一个功能,串口会返回接收到的数据。其原理是,当串口接收到1(注1)个数据以后,DMA将数据搬移到rx_buf(注2)数组中,完成后调用回到函数HAL_UART_RxCpltCallback(),而该函数会将rx_buf数组的值打印出来。

由 HAL_UART_Receive_DMA 第三个参数决定
由 HAL_UART_Receive_DMA 第二个参数决定

4. DMA 的回调函数的理解

这里再简单介绍一下DMA的回到函数,当串口数据传输完成,传输错误,传输一半,DMA 会调用回到函数,以下是HAL库HAL_UART_Transmit_DMA()函数的定义,可以发现库是在这里注册了回调函数:


    HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size)
    {
      /* Check that a Tx process is not already ongoing */
      if(huart->gState == HAL_UART_STATE_READY)
      {
        if((pData == NULL ) || (Size == 0U))
        {
          return HAL_ERROR;
        }
    
        /* In case of 9bits/No Parity transfer, pData buffer provided as input paramter 
           should be aligned on a u16 frontier, as data copy into TDR will be 
           handled by DMA from a u16 frontier. */
        if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))
        {
          if((((uint32_t)pData)&1U) != 0U)
          {
            return  HAL_ERROR;
          }
        }
    
        /* Process Locked */
        __HAL_LOCK(huart);
    
        huart->pTxBuffPtr = pData;
        huart->TxXferSize = Size;
        huart->TxXferCount = Size;
    
        huart->ErrorCode = HAL_UART_ERROR_NONE;
        huart->gState = HAL_UART_STATE_BUSY_TX;
    
        /* Set the UART DMA transfer complete callback */
        huart->hdmatx->XferCpltCallback = UART_DMATransmitCplt;
    
        /* Set the UART DMA Half transfer complete callback */
        huart->hdmatx->XferHalfCpltCallback = UART_DMATxHalfCplt;
    
        /* Set the DMA error callback */
        huart->hdmatx->XferErrorCallback = UART_DMAError;
    
        /* Set the DMA abort callback */
        huart->hdmatx->XferAbortCallback = NULL;
    
        /* Enable the UART transmit DMA channel */
        HAL_DMA_Start_IT(huart->hdmatx, (uint32_t)huart->pTxBuffPtr, (uint32_t)&huart->Instance->TDR, Size);
    
        /* Clear the TC flag in the ICR register */
        __HAL_UART_CLEAR_FLAG(huart, UART_CLEAR_TCF);
    
        /* Process Unlocked */
        __HAL_UNLOCK(huart);
    
        /* Enable the DMA transfer for transmit request by setting the DMAT bit
           in the UART CR3 register */
        SET_BIT(huart->Instance->CR3, USART_CR3_DMAT);
    
        return HAL_OK;
      }
      else
      {
        return HAL_BUSY;
      }
    }

从以上代码可以看出,UART_DMATransmitCplt()函数是传输完成的回调函数,进一步跟踪代码可以发现,在本例代码中,它最终调用的是串口发送完成的回调函数,这里虽然用户可以修改,但是非常不建议,毕竟作为CubeMx生成的代码下一次刷新又会改变到。我们可以重新定义串口发送完成回调函数:

/* USER CODE BEGIN 0 */
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	uint8_t tx_str[] = "Data Transfer completed\r\n";
	HAL_UART_Transmit(&huart1,tx_str,sizeof(tx_str),200);
}

/* USER CODE END 0 */

添加这段代码到工程中,比如main.c后,可以发现发送完数据后,串口打印出“Data Transfer completed ”的提示信息,运行程序结果如下:
在这里插入图片描述

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

STM32F0x HAL库学习笔记(7)DMA数据的传输配置:串口数据的DMA发送与接收 的相关文章

  • tensorflow 1.13.1 安装采坑

    环境 win10 x64位 cuda10 1 cudnn 7 5 vs2013 vs2015 distributed GTX1060 按照网上的教程安装 如下面博客 https blog csdn net huanyingzhizai ar
  • Android WebView打不开网页

    今天给公司前端同事打了个webview测试包 发现页面打不开 有两个原因 1 测试webview包没有配置好 特别是缓存没配置的同事用到h5缓存就打不开了 正确配置如下 设置支持javascript webView getSettings
  • Python第三方拓展包(安装下载方法)

    找到安装的位置 第一种方法 Anaconda集成环境 Anaconda集成环境 优点太多了 百度一大堆介绍 Anaconda的优点总结起来就八个字 省时省心 分析利器 省时省心 Anaconda通过管理工具包 开发环境 Python版本 大
  • JS点击计数存储案例

    项目功能要求 点击页面红色块默认不计数 点击开始按钮后再点击红色块则开始计数 点击结束按钮后再点击红色块则不计数 关闭页面并再次打开页面 界面会显示上次关闭页面时的计数值 代码设计 本项目结合了前端页面的设计和JS的使用 具体代码如下
  • 编译器工具 Flex Bison for Windows 简单入门例子

    最近从事一个系统仿真软件的开发 里面定义了自己的描述性语言MSL MSL语言经FlexBison转换成C语言 然后用C编译器来编译并计算仿真 现在领域驱动开发比较热门 有机会定义自己的语言对程序员来说是比较有成就感的 免不了要去学习编译原理
  • 笔记本电脑电池怎么拆_笔记本电脑电池的容量单位是Wh,手机是mAh,二者怎么比较?...

    Hello大家好 我是兼容机之家的小牛 目前很多轻薄本都搭载了全功能的Type C接口 大都支持PD充电 所以有的机友出门的时候就不会带上笔记本的 板砖 适配器了 往往会选择购买一个手机 电脑通用的PD充电器 大家平时都知道自己的手机电量是
  • steam创客教室

    人生不同阶段都有不同的使命 在学生阶段 学习掌握知识 为他们以后的人生获得成就的能力 就是他们这个阶段最重要的使命 格物斯坦小坦克的学生生涯也是这样做的 为了这个使命 他们必须要学习忍耐 学会放弃 学会付出 这不仅仅是学习的需要 也是人生的
  • 用 Python 爬取股票实时数据

    今天我们一起来学习一个 Python 爬虫实战案例 我们的目标网站就是东方财富网 废话不多说 开搞 网站分析 东方财富网地址如下 http quote eastmoney com center gridlist html hs a boar
  • 解读Android LOG机制的实现:(5)获取LOG的应用程序LogCat

    解读Android LOG机制的实现 5 获取LOG的应用程序LogCat 田海立 CSDN 2011 07 27 Android提供的LOG机制的实现贯穿了Java JNI 本地c c 实现以及LINUX内核驱动等Android的各个层次
  • 三步教你实现MyEclipse的debug远程调试

    MyEclipse远程调试程序是个神奇的东西 有时一个项目本地运行没问题可放到服务器上 同样的条件就是结果不一样 有时服务器上工程出点问题需要远程调测 于是就灰常想看一下程序在远程运行时候的状态 希望让程序在远程运行 还可以在本机打断点跟一
  • 执行力的关键在于中层,成败的关键在于细节

    编者注 这是一位国内著名企业总裁在一次工作会议上的讲话 文中说到完美的 细节 一定是完美执行力的结果 并且切中时弊的指出 执行力的关键在于中层 如何做到这一点 关键就是要建立一个保证中层执行力到位的强势文化 也许真正落实到位 不但首先会冲击
  • Nodejs

    一 是什么 中间件 Middleware 是介于应用系统和系统软件之间的一类软件 它使用系统软件所提供的基础服务 功能 衔接网络上应用系统的各个部分或不同的应用 能够达到资源共享 功能共享的目的 在NodeJS中 中间件主要是指封装http
  • 华为OD机试 - 阿里巴巴找黄金宝箱(IV)(Java)

    题目描述 一贫如洗的樵夫阿里巴巴在去砍柴的路上 无意中发现了强盗集团的藏宝地 藏宝地有编号从0 N的箱子 每个箱子上面有一个数字 箱子排列成一个环 编号最大的箱子的下一个是编号为0的箱子 请输出每个箱了贴的数字之后的第一个比它大的数 如果不
  • java爱心效果代码来了

    爱心 代码来了 村上春树说 仪式是一件很重要的事 现实生活被琐事充斥 仪式感总是被人遗忘 凑合的晚饭 乱丢的衣物 杂乱无章的生活让原本平淡的生活过得一潭死水 找不到生活的乐趣 童话 小王子 里狐狸对小王子说 你最好在每天相同的时间来 比如你
  • scrapy提高爬取速度

    scrapy在单机跑大量数据的时候 在对settings文件不进行设置的时候 scrapy的爬取速度很慢 再加上多个页面层级解析 往往导致上万的数据可能爬取要半个小时之久 这还不包括插入数据到数据库的操作 下面是我在实验中测试并且验证爬取速
  • Docker 之桥接网络(一)

    参考 https docs docker com network bridge 在网络方面 桥接网络是一个链路层设备 它在网络段之间转发流量 网桥可以是运行在主机内核中的硬件设备或软件设备 就Docker而言 桥接网络使用软件桥 允许连接到
  • Windows下配置环境变量

    Windows下配置环境变量 在安装某些软件或者应用程序时 需要配置环境变量 以便在后续可以正常使用 环境变量相当于给系统或用户应用程序设置一些参数 具体起什么作用和对应的环境变量相关 比如path 是告诉系统 当要求系统运行一个程序而没有
  • React 18的新特新

    React 18 最新的特性 批处理文件 在同一个 函数中 调用多次 useState 也只是会更新一次 function App const count setCount useState 0 const flag setFlag use
  • 基于51单片机的水位液位温度监测鱼缸系统仿真原理图程序

    硬件设计 上一篇咱们讲了基于数码管显示的液位检测 本章讲一下基于LCD1602显示的液位检测 同时伴有温度测量 该系统可应用于鱼缸 水塔 水箱的检测 本系统液位检测方案是基于液位传感器 通过传感器嵌入液体反馈回电信号 通过电信号的大小可以反

随机推荐

  • 如何利用python将一个list中的数字提取,然后求和?

    coding UTF 8 import re name score list u 唐僧 100 u 猪八戒 60 u 孙悟空 95 u 沙和尚 80 1 将score list列表转换为以 为分隔符的字符串 name score list
  • 极限学习机ELM原理与实现

    极限学习机 ELM 是当前一类非常热门的机器学习算法 被用来训练单隐层前馈神经网络 SLFN 本篇博文尽量通俗易懂地对极限学习机的原理进行详细介绍 之后分析如何用python实现该算法并对代码进行解释 1 算法的原理 极限学习机 ELM 用
  • 【STM32】 JDY-31蓝牙模块

    目录 一 介绍 二 模块特点 三 产品应用范围 四 模块技术参数 五 模块接口说明 六 蓝牙模块接口电路图 七 蓝牙模块实物图 一 介绍 蓝牙模块是指集成蓝牙功能的芯片基本电路集合 用于无线网络通讯 本蓝牙模块就是为了只能无线数据传输而专门
  • 微服务 - 拆分微服务的问题和拆分方法

    概述 现在被谈论最多的就是微服务和中台系统 我个人的理解是微服务或者是中台好不好 主要看实际的业务场景 架构的变迁往往需要耗费很大的学习成本和时间成本 所以更改架构的时候要三思而后行 适合自己特别重要 由单体到多应用的演变 从我入职开始 公
  • 变压器哪些部位易造成渗油?

    变压器哪些部位易造成渗油 答 1 套管升高座电流互感器小绝缘子引出线的桩头处 所有套管引线桩头 法兰处 2 气体继电器及连接管道处 3 潜油泵接线盒 观察窗 连接法兰 连接螺丝紧固件 胶垫 4 冷却器散热管 5 全部连接通路碟阀 6 集中净
  • [前端] vue开发的项目用ajax发送请求携带cookie

    只需要在main js中写这三行代码即可 import axios from axios axios defaults withCredentials true 让ajax携带cookie Vue prototype axios axios
  • 初谈 ChatGPT

    引子 最近 小编发现互联网中的大 V 突然都在用 ChatGPT 做宣传 ChatGPT不会淘汰你 能驾驭ChatGPT的人会淘汰你 带领一小部分人先驾驭ChatGPT 确实 ChatGPT这个新生事物 如今被视为蒸汽机 电脑 iPhone
  • 众所周知,YouTube是个学习网站

    大数据文摘出品 来源 medium 编译 Hippo 国内有小破站 国外有YouTube 就像国内的b站一样 YouTube不仅是一个多媒体娱乐帝国 还是一个全面的学习平台 每月无需支付订阅费即可在YouTube上观看视频 所有供你观看和学
  • dev GridControl 按条件纵向合并单元格

    dev GridControl 按条件纵向合并单元格 gridView5 OptionsView AllowCellMerge true gridView5 CellMerge gridView5 CellMerge 自定义合并单元格监听事
  • npm安装报错 npm ERR! code ERESOLVE npm ERR! ERESOLVE unable to resolve dependency tree

    项目场景 安装npm报错npm ERR code ERESOLVE npm ERR ERESOLVE unable to resolve dependency tree 原因分析 ERESOLVE与npm 7 x的问题 7 x有些处理检测比
  • 黑马JVM总结(十五)

    1 GC 相关参数 2 GC 分析1 下面通过一个案例去读懂垃圾回收的一个过程 学会读懂垃圾回收的日志 XX UseSerialGC 是一个垃圾回收器 jdk8下默认的垃圾回收器不是它 改为UseSerialGC它的幸存区的比例才不会调整
  • Jenkins系列(五)----Jenkins自动发布spring-boot应用

    一 测试环境 三台服务器来测试 一台SVN服务器 一台Jenkins服务器 一台应用服务器 如下 Jenkins服务器 192 168 84 100 SVN服务器 192 168 84 105 应用服务器 192 168 84 101 二
  • 第二篇:Spring Boot整合JPA、事务处理及AOP的使用

    一 Spring Boot整合JPA的具体步骤 注 Spring Boot整合JPA 源码下载 注 springboot学习资料汇总 参考 spring data jpa的使用 参考 Spring Cloud微服务实战 作者 参考 方志朋博
  • SQLyog软件里无法插入中文(即由默认的latin1改成UTF8编码格式)

    问题详情 无法插入中文 解决办法 需要修改编码格式 由默认的latin1改为utf8 改成 成功
  • ZZULIOJ 2829: 闯关游戏 (DP)

    2829 闯关游戏http acm zzuli edu cn problem php id 2829 include
  • 计算机专业名称bios翻译,bios英文翻译 最全BIOS设置中英文对照表

    对于熟悉电脑的人来说 设置BIOS是一件非常简单的事情 但对于小白来说 别说设置BIOS了 看不看得懂这些乱七八糟的英文都很难说 为了熟悉重装系统的教程 有写用户会在虚拟机上去尝试 今天小编就为你们翻译出BIOS的英文 不懂英文的小伙伴们赶
  • Linux线程:创建(pthread_create),等待(pthread_join),退出(pthread_exit)

    目录 一 线程说明 线程与进程 线程优点 线程缺点 二 线程开发API概要 三 线程控制流程 线程创建 pthread create 线程退出 pthread exit 线程等待 pthread join 线程脱离 pthread deta
  • java超详细小程序对接微信支付(二),看完不会你打我

    4 支付通知回调 B 验证签名 因为这个接口是微信进行回调的 但是如果别人知道了这个接口就给进行伪造信息进行调用这个接口 补充一点 这里这个接口最后要返回给微信success 不然会一直进行调用该接口 以下是我封装的验证签名的方法 要给的参
  • Datawhale go语言学习 12并发编程

    12 并发编程 12 1 并发与并行 Erlang 之父 Joe Armstrong曾经以下图解释并发与并行 外链图片转存失败 源站可能有防盗链机制 建议将图片保存下来直接上传 img u21Pi0Ef 1608215197628 img
  • STM32F0x HAL库学习笔记(7)DMA数据的传输配置:串口数据的DMA发送与接收

    本文开发环境 MCU型号 STM32F051R8T6 IDE环境 MDK 5 25 代码生成工具 STM32CubeMx 5 0 1 HAL库版本 v1 9 0 STM32Cube MCU Package for STM32F0 Serie