[其他ST产品] STM32CubeMX配置ADC采样(轮询、中断、DMA)

[复制链接]
2882|76
 楼主| 工程师犹饿死 发表于 2023-4-18 22:57 | 显示全部楼层
在adc.c文件中加入上面代码,HAL_ADC_ConvCpltCallback是ADC中断的回调函数,其原型是个弱函数,重新定义后原来的函数就失去作用了

60841643eafd91e715.png
 楼主| 工程师犹饿死 发表于 2023-4-18 22:57 | 显示全部楼层
最后将adc.c文件中的通道转换结束标准修改为ADC_EOC_SEQ_CONV,否则只会进入一次中断
ADC_EOC_SEQ_CONV:在所有通道转换完成后进入中断
ADC_EOC_SINGLE_CONV:单个通道转换完成后进入中断
多个通道时,两种均可采用,单通道采样时需使用ADC_EOC_SEQ_CONV才能连续进入中断(经测试)
 楼主| 工程师犹饿死 发表于 2023-4-18 22:58 | 显示全部楼层
最后将程序下载到单片机中,现象如下:
98085643eb0019682c.png
 楼主| 工程师犹饿死 发表于 2023-4-18 22:58 | 显示全部楼层
方法二:
我们利用HAL_ADC_Start_IT开启adc中断,该函数比较特殊,调用一次该函数就打开了ADC转换完成中断和开启ADC采样
16283643eb0205dfe8.png
79800643eb02b25248.png
 楼主| 工程师犹饿死 发表于 2023-4-18 22:59 | 显示全部楼层
在主函数中直接调用HAL_ADC_Start_IT即可
 楼主| 工程师犹饿死 发表于 2023-4-18 22:59 | 显示全部楼层
3、单通道DMA

dma有两种模式,分别为circular和normal
circular模式:dma的circular模式只需要调用一次dma开启函数,dma就会持续的搬运数据,提高了数据的刷新速度,但是在circular模式下,不管adc新的一轮数据采集是否完成,有可能直接将旧数据搬运走
normal模式:该模式下,dma启动函数调用一次,dma通道只会搬运一次数据,这样每调一次dma启动函数,dma只会搬运一次数据,等待数据传输完成后再次开启dma启动函数,这样更能保证adc数据采集的可靠性
 楼主| 工程师犹饿死 发表于 2023-4-18 22:59 | 显示全部楼层
circular模式:
cubemux配置步骤如下(时钟配置等已略去):
49771643eb063d7096.png
 楼主| 工程师犹饿死 发表于 2023-4-18 23:00 | 显示全部楼层
修改ADC采样时间,通常采样时间越长,adc采样精度越高
89762643eb07785223.png
 楼主| 工程师犹饿死 发表于 2023-4-18 23:00 | 显示全部楼层
选用dma的circular模式
88201643eb08d64663.png
 楼主| 工程师犹饿死 发表于 2023-4-18 23:00 | 显示全部楼层
返回开启dma连续请求(若不开启,只能进入一次dma采集完成中断函数)

  1. uint16_t AD_value=0;
  2. float f_AD_value;
 楼主| 工程师犹饿死 发表于 2023-4-18 23:01 | 显示全部楼层
打开工程文件,在文件中添加上面代码,AD_value用于保存测量的adc原值,f_AD_value保存计算得到的电压值
  1. HAL_ADC_Start_DMA(&hadc1,(uint32_t*)&AD_value,sizeof(AD_value));
 楼主| 工程师犹饿死 发表于 2023-4-18 23:01 | 显示全部楼层
在主函数中调用HAL_ADC_Start_DMA开启adc采样,同时开启dma传输数据(调用一次即可)

19667643eb0c7c2966.png
 楼主| 工程师犹饿死 发表于 2023-4-18 23:01 | 显示全部楼层
最后在dma中断函数中添加上述代码,将adc采集完成的数据打印出来
 楼主| 工程师犹饿死 发表于 2023-4-18 23:02 | 显示全部楼层
normal模式:
normal模式下,我们的想法是调用一次HAL_ADC_Start_DMA函数,adc进行一次数据采集,dma搬运一次数据,我们在上面配置完成的代码中做简单修改就能实现
40217643eb0e51c927.png
 楼主| 工程师犹饿死 发表于 2023-4-18 23:02 | 显示全部楼层
关闭adc连续采集模式,这样开启一次adc,只会进行一次数据采集
13626643eb0f817f8c.png
 楼主| 工程师犹饿死 发表于 2023-4-18 23:02 | 显示全部楼层
将dma模式修改为normal
7260643eb1086496f.png
 楼主| 工程师犹饿死 发表于 2023-4-18 23:02 | 显示全部楼层
修改dma中断函数

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



最后在主函数中调用HAL_ADC_Start_DMA开启adc采样,同时开启dma传输数据(每调用一次只会采集一次数据)
 楼主| 工程师犹饿死 发表于 2023-4-18 23:03 | 显示全部楼层
4、多通道轮询
67610643eb1322f08b.png
这里用ADC1的通道IN0、IN1、IN2、IN3四个通道作演示,多个通道时必须开启间断模式,并且每个间断组中只有一个通道,否则每次只能读取到每组最后一个通道的值
 楼主| 工程师犹饿死 发表于 2023-4-18 23:03 | 显示全部楼层
78869643eb13ab55a7.png

设置通道转换顺序

  1. uint16_t AD_value[4]={0};
 楼主| 工程师犹饿死 发表于 2023-4-18 23:03 | 显示全部楼层
打开工程文件,创建一数组用于存储四个通道的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是阻塞时间
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部