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

8 篇文章 9 订阅
8 篇文章 2 订阅

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
在这里插入图片描述
这样就能连续采集打印数据了

  • 71
    点赞
  • 461
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Sense_long

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值