一、非DMA模式(转)

  说明:这个是自己刚做的时候百度出来的,不是我自己做出来的,因为感觉有用就保存下来做学习用,原文链接:https://blog.csdn.net/qq_24815615/article/details/70227385,下面第二部分我会补充自己的DMA模式的方法。

  Stm32 ADC 的转换模式还是很灵活,很强大,模式种类很多,那么这也导致很多人使用的时候没细心研究参考手册的情况下容易混淆。不知道该用哪种方式来实现自己想要的功能。网上也可以搜到很多资料,但是大部分是针对之前老版本的标准库的。昨天帮客户解决这个问题,正好做个总结:使用stm32cubeMX配置生成多通道采集的例子。

软件:STM32Cumebx  MDK

硬件:eemaker板(基于stm32F103c8的)

在百度搜索ADC多通道采集,大部分的都是基于采用dma模式才实现的。而我讲的使用非dma方法。首先有几个概念要搞清楚:

  扫描模式(想采集多通道必须开启):是一次对所选中的通道进行转换,比如开了ch0,ch1,ch4,ch5。Ch0转换完以后就会自动转换通道0,1,4,5直到转换完。但是这种连续性并不是不能被打断。这就引入了间断模式,可以说是对扫描模式的一种补充。它可以把0,1,4,5这四个通道进行分组。可以分成0,1一组,4,5一组。也可以每个通道配置为一组。这样每一组转换之前都需要先触发一次。

  Stm32 ADC的单次模式和连续模式。这两中模式的概念是相对应的。这里的单次模式并不是指一个通道。假如你同时开了ch0,ch1,ch4,ch5这四个通道。单次模式转换模式下会把这四个通道采集一边就停止了。而连续模式就是这四个通道转换完以后再循环过来再从ch0开始。

  另外还有规则组和注入组的概念,因为我这个例程只用到了规则组,就不多介绍这两个概念,想要弄清楚请自行查阅手册。

下面进入正题,配置stm32cubeMX。

先使能几个通道,我这里设置为0、1、4、5.

然后就要配置ADC的参数:

  目前经过我的测试,要想用非dma和中断模式只有这样配置可以正确进行多通道转换:扫描模式+单次转换模式+间断转换模式(每个间断组一个通道)。

  分析配置成这样的模式,扫描模式是在配置为多个通道必须打开的,stm32cubeMX上也默认好了,只能enable。单次转换模式是我不需要不停的去采集每个通道值,而是把四个通道采集完以后就让它停止。这里间断配置是关键,间断模式可以让扫描的四个通道进行分成四个组,stm32cubeMX参数里面number of Discontinous Conversions是配置间断组每个组有几个通道的,这里必须配置为1(否则在获取ad值得时候只能读取到每个间断组最后一个通道)。

生成mdk工程代码。这时候还没有完成,只是实现了ADC的初始化,需要采集这四个通道值得函数还要自己写。下面这个是我main函数的while循环:

  1. for(i=;i<;i++)
  2.  
  3. {
  4.  
  5. HAL_ADC_Start(&hadc1);
  6.  
  7. HAL_ADC_PollForConversion(&hadc1,0xffff);//等待ADC转换完成
  8.  
  9. adcBuf[i]=HAL_ADC_GetValue(&hadc1);
  10.  
  11. printf("------ch:%d--%d-------\r\n",i,adcBuf[i]);
  12.  
  13. }
  14.  
  15. HAL_ADC_Stop(&hadc1);
  16.  
  17. HAL_Delay();

  调用hal库接口函数也需要注意,HAL_ADC_Start一定要放在for里面,即每一个通道都要触发。四个通道都采集完了,再去调用HAL_ADC_Stop(&hadc1);结束本次ADC采集。

二、DMA模式

  下面就是我自己的DMA模式的ADC多通道转换了。

  先配置一些ADC的基本配置:

  引脚

  时钟

  这个时钟可以结合ADC设置里配置的采样时间结合计算出ADC转换的时间,进而换算出频率。

  接着配置DMA

  ADC是12位的,其实DMA只需要用Half Word就可以了,但实际中HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length);
该函数中pData为32位的,也就是DMA必须配置为Word才可以。

 配置ADC基本设置 

  这里要注意选择对不同的通道,一开始我就是没留意到这个问题,就只有一个通道 Channel10 在转换,后来查看就是Rank1、2、3全配置成  Channel10 了,所以只有这个通道在转换,这里这个提醒大家注意一下。

  中断配置

  最后在main文件的main函数里的while循环里加入下面代码

  1. HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&AD_DMA, ); //启用DMA的ADC转换,AD_DMA 0~3 对应ADC 0~3,这里注意最后一个参数的大小
  2. printf("AD_DMA_0 = %d\r\n",AD_DMA[]);
  3. printf("AD_DMA_1 = %d\r\n",AD_DMA[]);
  4. printf("AD_DMA_2 = %d\r\n",AD_DMA[]);
  5. HAL_Delay();

  注意:在while循环前要加ADC校准

  1. HAL_ADCEx_Calibration_Start(&hadc1); //AD校准

  串口打印结果如下,至于怎样串口打印这里就不多说了,想知道的可以看https://www.cnblogs.com/xingboy/p/9522940.html

  

补充:使用定时器与DMA中断定时采集

  上面只是单纯的一直采集的,如果想要用到中断的话就可以按下面的方式来,ADC配置跟上面说的DMA模式一样:

  先配置定时器中断,怎么配置可以参考我的另一个文章https://www.cnblogs.com/xingboy/p/9897500.html

  接着在 main 函数的 while 循环前打开定时器中断

  1. HAL_TIM_Base_Start_IT(&htim3); //启动定时器中断

  然后重写定时器中断回调函数

  1. void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
  2. {
  3. HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&AD_DMA, ); //启用DMA的ADC转换,AD_DMA 0~3 对应ADC 0~3,这里注意最后一个参数的大小
  4. }

  这里要注意了,我调试的时候发现HAL_ADC_Start_DMA()函数中最后一个参数的大小起码要比你定义的AD_DMA数组大2,不过不能大于2倍,前面的使用这个函数的时候也是要这样,数据太小,会导致后面的AD通道采集不了数据,大于2倍程序会一直卡住,至于为什么这样子我也还没搞懂,知道的可以告诉我一声。【补充:关于这个参数大小的问题,我查了一些资料,一般ADC每次读进来的数据都是2个字节大小的半字,所以3个通道读进来的一般一次6个字节这样,4个通道类似,而这里的最后一个参数代表的就是要传输的字节数,所以这个参数要根据通道个数设置,通常ADC读入一个半字,也就是uint16_t,你设为Word,那么会去读一个uint32_t是4个字节,其实这个我也还不是很懂,不知道对不对的欢迎大家指出】

  最后写DMA中断服务函数

  1. void DMA1_Channel1_IRQHandler(void)
  2. {
  3. /* USER CODE BEGIN DMA1_Channel1_IRQn 0 */
  4.  
  5. /*自己添加代码部分*/
  6. HAL_ADC_Stop_DMA(&hadc1); //停止DMA的ADC转换,AD_DMA 0~3 对应ADC 0~3
  7. HAL_TIM_Base_Stop_IT(&htim3);//关闭定时器
  8. printf("AD_DMA_0 = %d\r\n",AD_DMA[]);
  9. printf("AD_DMA_1 = %d\r\n",AD_DMA[]);
  10. printf("AD_DMA_2 = %d\r\n",AD_DMA[]);
  11. HAL_TIM_Base_Start_IT(&htim3); //重新开启定时器
  12.  
  13. /* USER CODE END DMA1_Channel1_IRQn 0 */
  14. HAL_DMA_IRQHandler(&hdma_adc1);
  15. /* USER CODE BEGIN DMA1_Channel1_IRQn 1 */
  16. //__HAL_DMA_CLEAR_FLAG(&hdma_adc1, __HAL_DMA_GET_TC_FLAG_INDEX(&hdma_adc1)); //清楚标志位
  17. /* USER CODE END DMA1_Channel1_IRQn 1 */
  18. }

  这样子,就可以实现1S采集多少次ADC了,而不用单纯控制采样频率来控制1S的ADC采集次数了,个人觉得单纯控制采样频率比较难算。

补充:单通ADC采集参考:https://www.cnblogs.com/xingboy/p/10018749.html

 补充一个 4 通道采集 DMA 模式:

  

  

  

  

  

定义一个数组存放DMA数据

  1. uint16_t AD_DMA[];

  直接在 main 函数的 while 前面开启 ADC校验跟采集

  1. HAL_ADCEx_Calibration_Start(&hadc1); //AD校准
  2. HAL_ADC_Start_DMA(&hadc1, (uint32_t *)&AD_DMA, ); //启用DMA的ADC转换,AD_DMA 0~3 对应ADC 0~3

  while函数里打印DMA的值

  1. printf("AD0 = %d\r\n",AD_DMA[]);
  2. printf("AD1 = %d\r\n",AD_DMA[]);
  3. printf("AD2 = %d\r\n",AD_DMA[]);
  4. printf("AD3 = %d\r\n",AD_DMA[]);
  5. HAL_Delay();

  打印结果如下

    

  

STM32 ADC多通道转换DMA模式与非DMA模式两种方法(HAL库)的更多相关文章

  1. STM32 ADC多通道转换

    描述:用ADC连续采集11路模拟信号,并由DMA传输到内存.ADC配置为扫描并且连续转换模式,ADC的时钟配置为12MHZ.在每次转换结束后,由DMA循环将转换的数据传输到内存中.ADC可以连续采集N ...

  2. DUI-分层窗口两种模式(SetLayeredWindowAttributes和UpdateLayeredWindow两种方法各有利弊)

    LayeredWindow提供两种模式: 1.使用SetLayeredWindowAttributes去设置透明度, 完成窗口的统一透明,此时窗口仍然收到PAINT消息, 其他应用跟普通窗口一样. 2 ...

  3. 将四个BYTE数值转换成IEEE754标准的浮点数(两种方法:用Addr函数取字节数字的首地址,或者用Absolute关键字)

    在工作中,经常使用到IEEE754格式的数据.IEEE754格式的数据占四个字节,好像Motorola格式和Intel格式的还不一样. 由于工作中很少和他打交道(使用的软件内部已经处理),就没太在意. ...

  4. stm32中阻塞模式和非阻塞模式 in blocking mode 与 in non-blocking mode区别

    阻塞模式和非阻塞模式...... 我的理解是:阻塞模式就像是一个延时函数,当这个函数没处理完那么,所有的按照流程需要执行的代码都不会被执行,要等到这个延时完成,类似 平时看书上写的LED灯闪烁,用的d ...

  5. Oracle之归档模式与非归档模式

    归档模式和非归档模式 在DBA部署数据库之初,必须要做出的最重要决定之一就是选择归档模式(ARCHIVELOG)或者非 归档模式(NOARCHIVELOG )下运行数据库.我们知道,Oracle 数据 ...

  6. Oracle归档模式和非归档模式的区别

    一.查看oracle数据库是否为归档模式: Sql代码1.select name,log_mode from v$database; NAME LOG_MODE ------------------ ...

  7. Oracle归档模式与非归档模式设置

    (转自:http://www.cnblogs.com/spatial/archive/2009/08/01/1536429.html) Oracle的日志归档模式可以有效的防止instance和dis ...

  8. 怎样将Oracle数据库设置为归档模式及非归档模式

    怎样将Oracle数据库设置为归档模式及非归档模式 1.Oracle日志分类 分三大类: Alert log files--警报日志,Trace files--跟踪日志(用户和进程)和 redo lo ...

  9. socket异步通信-如何设置成非阻塞模式、非阻塞模式下判断connect成功(失败)、判断recv/recvfrom成功(失败)、判断send/sendto

    socket异步通信-如何设置成非阻塞模式.非阻塞模式下判断connect成功(失败).判断recv/recvfrom成功(失败).判断send/sendto 博客分类: Linux Socket s ...

随机推荐

  1. SEAndroid安全机制框架分析

    我们知道,Android系统基于Linux实现. 针对传统Linux系统,NSA开发了一套安全机制SELinux,用来加强安全性. 然而.因为Android系统有着独特的用户空间执行时.因此SELin ...

  2. jquery 页眉单行信息滚动显示

    JSP: 下面是控制滚动的样式.将滚动的内容查询出来.放在一个div 或者别的容器里面,我这里使用的是<dt> <style> #newCglist{width:300px;h ...

  3. SRV记录用来标识某台服务器使用了某个服务,常见于微软系统的目录管理——深入的话需要去折腾Azure Active Directory

    SRV记录 SRV记录 什么情况下会用到SRV记录? [SRV记录用来标识某台服务器使用了某个服务,常见于微软系统的目录管理] SRV记录的添加方式 A.主机记录处格式为:服务的名字.协议的类型 例如 ...

  4. 杂项-SpringEureka:笔记-1

    ylbtech-杂项-SpringEureka:笔记-1 1.返回顶部 1. THE SELF PRESERVATION MODE IS TURNED OFF.THIS MAY NOT PROTECT ...

  5. [Javascript] 轻量级的JavaScript日期处理类库xDate使用指南

    XDate是一个请谅解的JavaScript的原生Date对象的封装库,提供增强的功能解析,格式化和日期处理.使用起来就和JavaScript自己的对象和方法一样,非常简单. XDate是一个请谅解的 ...

  6. SwiftUI 官方教程(三)

    3. 用 Stacks 组合 View 在上一节创建标题 view 后,我们来添加 text view,它用来显示地标的详细信息,比如公园的名称和所在的州. 在创建 SwiftUI view 时,我们 ...

  7. php对文件/目录操作的基础知识(图解)

    具体的如下图所示:

  8. C++数字图像处理(1)-伽马变换

    https://blog.csdn.net/huqiang_823/article/details/80767019 1.算法原理    伽马变换(幂律变换)是常用的灰度变换,是一种简单的图像增强算法 ...

  9. Solr.NET快速入门(三)【高亮显示】

    此功能会"高亮显示"匹配查询的字词(通常使用标记),包括匹配字词周围的文字片段. 要启用高亮显示,请包括HighlightingParameters QueryOptions对象, ...

  10. MapReduce架构与生命周期

    MapReduce架构与生命周期 概述:MapReduce是hadoop的核心组件之一,可以通过MapReduce很容易在hadoop平台上进行分布式的计算编程.本文组织结果如下:首先对MapRedu ...