草庐IT

STM32CubeMX配置ADC采样(轮询、中断、DMA)

Sense_long 2023-07-11 原文

STM32CubeMX能够极大减小STM32外设配置的工作量,因此作者也借助空闲时间对STM32CubeMX相关配置进行了学习,本文介绍如何利用STM32CubeMX配置ADC采样,记录了作者学习过程中遇到的问题及解决办法,使大家少走弯路,并方便以后复习

目录

1、单通道轮询


先选择所使用的MCU,这里我使用的是STM32F407ZGT系列

修改一下DEBUG功能,否则后续无法调试

修改时钟,采用外部晶振

配置一串口,用于打印采集的ADC值

这里我采用ADC1的通道0,并开启连续采样模式,否则每次开启ADC采样后只进行一次采样

开启ADC全局中断(如果只采用轮询采样就不用开启,这里开启是为了方便后面演示中断采样

修改一下ADC全局中断的优先级

在HCLK处输入其时钟最高频率168,按回车,其余时钟会自动配置好,一般情况下无需改动


勾选上后,每个外设会单独保存至一个.c文件,便于查看


生成并打开文件

在main.h中包含头文件stdio.h

在usart.c文件中加入fputc函数,加入后才能使用printf函数进行打印数据

在while循环中添加以上代码,由于开启了连续转换模式,即hadc1.Init.ContinuousConvMode = ENABLE;因此每次转换完成后都要调用HAL_ADC_Stop来关闭ADC;如果不想每次都调用该函数来关闭ADC,可以关闭连续转换模式,即hadc1.Init.ContinuousConvMode = DISABLE,这样每次开启ADC转换以后只会进行一次采样,这样就不需要每次都关闭ADC了
实验现象如下图:

2、单通道中断

单通道中断采样配置过程与单通道轮询采样相同,利用cubemx配置完成后有两种开始ADC采样的方法
方法一

在主函数中加入上述代码,__HAL_ADC_ENABLE_IT(&hadc1,ADC_IT_EOC);用于打开ADC转换完成中断,HAL_ADC_Start(&hadc1);用于开启ADC采样,这两个函数一定要放到外设初始化函数的后面,否则串口函数初始化未完成,在ADC中断中使用printf函数可能会卡死

在adc.c文件中加入上面代码,HAL_ADC_ConvCpltCallback是ADC中断的回调函数,其原型是个弱函数,重新定义后原来的函数就失去作用了

最后将adc.c文件中的通道转换结束标准修改为ADC_EOC_SEQ_CONV,否则只会进入一次中断
ADC_EOC_SEQ_CONV:在所有通道转换完成后进入中断
ADC_EOC_SINGLE_CONV:单个通道转换完成后进入中断
多个通道时,两种均可采用,单通道采样时需使用ADC_EOC_SEQ_CONV才能连续进入中断(经测试)

最后将程序下载到单片机中,现象如下:

方法二
我们利用HAL_ADC_Start_IT开启adc中断,该函数比较特殊,调用一次该函数就打开了ADC转换完成中断开启ADC采样

在主函数中直接调用HAL_ADC_Start_IT即可

3、单通道DMA

dma有两种模式,分别为circular和normal
circular模式:dma的circular模式只需要调用一次dma开启函数,dma就会持续的搬运数据,提高了数据的刷新速度,但是在circular模式下,不管adc新的一轮数据采集是否完成,有可能直接将旧数据搬运走
normal模式:该模式下,dma启动函数调用一次,dma通道只会搬运一次数据,这样每调一次dma启动函数,dma只会搬运一次数据,等待数据传输完成后再次开启dma启动函数,这样更能保证adc数据采集的可靠性
circular模式:
cubemux配置步骤如下(时钟配置等已略去):

这里我们同样用ADC1的通道IN0来测试,开启adc连续采集模式

修改ADC采样时间,通常采样时间越长,adc采样精度越高

选用dma的circular模式

返回开启dma连续请求(若不开启,只能进入一次dma采集完成中断函数

 uint16_t AD_value=0;
 float f_AD_value;

打开工程文件,在文件中添加上面代码,AD_value用于保存测量的adc原值,f_AD_value保存计算得到的电压值

 HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&AD_value,sizeof(AD_value));

在主函数中调用HAL_ADC_Start_DMA开启adc采样,同时开启dma传输数据(调用一次即可

最后在dma中断函数中添加上述代码,将adc采集完成的数据打印出来
normal模式:
normal模式下,我们的想法是调用一次HAL_ADC_Start_DMA函数,adc进行一次数据采集,dma搬运一次数据,我们在上面配置完成的代码中做简单修改就能实现

关闭adc连续采集模式,这样开启一次adc,只会进行一次数据采集

将dma模式修改为normal

修改dma中断函数

 HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&AD_value,sizeof(AD_value));

最后在主函数中调用HAL_ADC_Start_DMA开启adc采样,同时开启dma传输数据(每调用一次只会采集一次数据

4、多通道轮询


这里用ADC1的通道IN0、IN1、IN2、IN3四个通道作演示,多个通道时必须开启间断模式,并且每个间断组中只有一个通道,否则每次只能读取到每组最后一个通道的值

设置通道转换顺序

uint16_t AD_value[4]={0};

打开工程文件,创建一数组用于存储四个通道的ADC值

for(i=0;i<4;i++){
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1,10);
AD_value[i]=HAL_ADC_GetValue(&hadc1);
printf("PA%d:%d\r\n",i,AD_value[i]);
printf("PA%d:%.3f v\r\n",i,AD_value[i]*3.3/4096);
}
HAL_Delay(500);

在主循环中添加上述代码,HAL_ADC_Start必须放在for循环中,否则只能采集第一个通道的ADC值;HAL_ADC_PollForConversion用于轮询转换,是一个阻塞函数,等待转换完成,参数10是阻塞时间

5、多通道中断

多通道情况下使用中断来读取数据理论上是可行的,但是读取的数据会混淆,即无法确定读取的数据是属于哪一个通道的,因此我们不使用

6、多通道DMA


开启DMA并采用circular模式

uint16_t AD_value[4]={0};

定义一数组用于保存ADC采样值

在外设初始化函数下面调用 HAL_ADC_Start_DMA(&hadc1,(uint32_t*)AD_value,sizeof(AD_value));启动ADC转换和DMA数据传输

最后在DMA接收完成中断中将采集到的ADC数据打印出来
经测试:DMA接收中断在数据接收缓冲区满了后触发,这里的缓冲区是数据AD_value[4]

注意:
通常为了方便使用一些滤波算法,我们可以将缓冲区数据创建的更大一些(为通道数的整数倍),这里我们采用了4个通道,我们可以将缓冲数组创建为AD_value[40]
则AD_value[0]、AD_value[4]、AD_value[8]…AD_value[36]均为通道IN0的值
AD_value[1]、AD_value[5]、AD_value[9]…AD_value[37]均为通道IN1的值,
AD_value[2]、AD_value[6]、AD_value[10]…AD_value[38]均为通道IN2的值,
AD_value[3]、AD_value[7]、AD_value[11]…AD_value[39]均为通道IN3的值,


我们同样在dma接收完成中断中将数据打印出来

实验现象如上,只打印了一次数据,表示只进入了一次DMA中断中,并且主循环中的程序也不再继续执行,程序卡死了

可以在进入DMA中断函数时调用HAL_ADC_Stop_DMA来关闭ADC采集,当需要采集ADC的时候再调用 HAL_ADC_Start_DMA即可,这里为了演示在中断函数结束时又重新开启了ADC

这样就能连续采集打印数据了

有关STM32CubeMX配置ADC采样(轮询、中断、DMA)的更多相关文章

  1. ruby-on-rails - 独立 ruby​​ 脚本的配置文件 - 2

    我有一个在Linux服务器上运行的ruby​​脚本。它不使用rails或任何东西。它基本上是一个命令行ruby​​脚本,可以像这样传递参数:./ruby_script.rbarg1arg2如何将参数抽象到配置文件(例如yaml文件或其他文件)中?您能否举例说明如何做到这一点?提前谢谢你。 最佳答案 首先,您可以运行一个写入YAML配置文件的独立脚本:require"yaml"File.write("path_to_yaml_file",[arg1,arg2].to_yaml)然后,在您的应用中阅读它:require"yaml"arg

  2. Ruby Sinatra 配置用于生产和开发 - 2

    我已经在Sinatra上创建了应用程序,它代表了一个简单的API。我想在生产和开发上进行部署。我想在部署时选择,是开发还是生产,一些方法的逻辑应该改变,这取决于部署类型。是否有任何想法,如何完成以及解决此问题的一些示例。例子:我有代码get'/api/test'doreturn"Itisdev"end但是在部署到生产环境之后我想在运行/api/test之后看到ItisPROD如何实现? 最佳答案 根据SinatraDocumentation:EnvironmentscanbesetthroughtheRACK_ENVenvironm

  3. Vscode+Cmake配置并运行opencv环境(Windows和Ubuntu大同小异) - 2

    之前在培训新生的时候,windows环境下配置opencv环境一直教的都是网上主流的vsstudio配置属性表,但是这个似乎对新生来说难度略高(虽然个人觉得完全是他们自己的问题),加之暑假之后对cmake实在是爱不释手,且这样配置确实十分简单(其实都不需要配置),故斗胆妄言vscode下配置CV之法。其实极为简单,图比较多所以很长。如果你看此文还配不好,你应该思考一下是不是自己的问题。闲话少说,直接开始。0.CMkae简介有的人到大二了都不知道cmake是什么,我不说是谁。CMake是一个开源免费并且跨平台的构建工具,可以用简单的语句来描述所有平台的编译过程。它能够根据当前所在平台输出对应的m

  4. STM32读取串口传感器数据(颗粒物传感器,主动上传) - 2

    文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,

  5. 神州数码无线产品(AC+AP)配置 - 2

    注意:本文主要掌握DCN自研无线产品的基本配置方法和注意事项,能够进行一般的项目实施、调试与运维AP基本配置命令AP登录用户名和密码均为:adminAP默认IP地址为:192.168.1.10AP默认情况下DHCP开启AP静态地址配置:setmanagementstatic-ip192.168.10.1AP开启/关闭DHCP功能:setmanagementdhcp-statusup/downAP设置默认网关:setstatic-ip-routegeteway192.168.10.254查看AP基本信息:getsystemgetmanagementgetmanaged-apgetrouteAP配

  6. hadoop安装之保姆级教程(二)之YARN的配置 - 2

    1.1.1 YARN的介绍 为克服Hadoop1.0中HDFS和MapReduce存在的各种问题⽽提出的,针对Hadoop1.0中的MapReduce在扩展性和多框架⽀持⽅⾯的不⾜,提出了全新的资源管理框架YARN. ApacheYARN(YetanotherResourceNegotiator的缩写)是Hadoop集群的资源管理系统,负责为计算程序提供服务器计算资源,相当于⼀个分布式的操作系统平台,⽽MapReduce等计算程序则相当于运⾏于操作系统之上的应⽤程序。 YARN被引⼊Hadoop2,最初是为了改善MapReduce的实现,但是因为具有⾜够的通⽤性,同样可以⽀持其他的分布式计算模

  7. ruby - ruby 乘法语句中星号中断语法前的空格 - 2

    在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl

  8. Ruby 默认将 IRB 配置为 Pretty_Inspect - 2

    我是ruby​​的新手,正在配置IRB。我喜欢pretty-print(需要'pp'),但总是输入pp来漂亮地打印它似乎很麻烦。我想做的是默认情况下让它漂亮地打印出来,所以如果我有一个var,比如说,'myvar',然后键入myvar,它会自动调用pretty_inspect而不是常规检查。我从哪里开始?理想情况下,我将能够向我的.irbrc文件添加一个自动调用的方法。有什么想法吗?谢谢! 最佳答案 irb中默认pretty-print对象正是hirb被迫去做。Theseposts解释hirb如何将几乎所有内容转换为ascii表。虽

  9. ruby - 在 ASP 页面上 Mechanize 中断 - 2

    require'mechanize'agent=Mechanize.newlogin=agent.get('http://www.schoolnet.ch/DE/HomeDE.htm')agent.clicklogin.link_withtext:/Login/然后我得到Mechanize::UnsupportedSchemeError。 最佳答案 Mechanize不支持javascript但您可以将搜索字段添加到表单并为其分配搜索词并使用mechanize提交表单form=page.forms.firstform.add_fie

  10. ruby - 是否可以将 IRB 提示配置为动态更改? - 2

    我想在IRB中浏览文件系统并让提示更改以反射(reflect)当前工作目录,但我不知道如何在每个命令后进行提示更新。最终,我想在日常工作中更多地使用IRB,让bash溜走。我在我的.irbrc中试过这个:require'fileutils'includeFileUtilsIRB.conf[:PROMPT][:CUSTOM]={:PROMPT_N=>"\e[1m:\e[m",:PROMPT_I=>"\e[1m#{pwd}>\e[m",:PROMPT_S=>"FOO",:PROMPT_C=>"\e[1m#{pwd}>\e[m",:RETURN=>""}IRB.conf[:PROMPT_MO

随机推荐