HAL库教程12:ADC与DMA采集多路AD值

AD的基础知识

  AD很复杂,其实也不复杂,因为我们用的不多。
  AD:模拟量转换数字量(模拟信号转换数字信号)。
  ADC:模拟量转数字量的转换器。
  为什么需要AD呢?
  自然界宏观的物理量都是连续的。而机器识别的信号0与1是离散的。为了让机器能够采集、分析、储存这些连续的量,所以要把需要被模拟的量转换为数字量。
  主要的参数:采样精度与转换速度。
  采样精度,也叫作分辨率。如果0-100摄氏度用8位AD来储存的话,精度计算?
  0000 0000 —— 0摄氏度
  1111 1111 —— 100摄氏度
  100/256 = 0.39摄氏度,0.39就是最小份的分辨率,也就是采样精度.没有办法表现出0.2度
  100/65536 = 0.0015,16位的AD,精度就很高了。
  转换速度
  从启动到出结果用的时间,一般来说越快越好。与精度不可兼得。被单位时间采样数量影响。采样多,速度不会很快。
  STM32F4使用的AD是逐次逼近型ADC,它产生一系列比较电压VR,但它是逐个产生比较电压,逐次与输入电压分别比较,以逐渐逼近的方式进行模数转换的。它比并联比较型ADC的转换速度慢,比双分积型ADC要快得多,属于中速ADC器件。

多通道AD采集需要使用DMA

  在STM32的手册中,我们发现,不论是单次采集还是多次采集,转换完成的数据都会放在同一个地方。
在这里插入图片描述
  由于DR寄存器不是一个数组,而是一个字节,所以只能保存最新的转换结果。例如,通道1和通道2都使用,通道1的转换结果放在DR寄存器。通道2转换完毕以后,就会覆盖通道1的结果。
  程序里,当然可以通过一些处理,让通道1的结果在被覆盖之前就保存好。不过,运用STM32的DMA功能,可以更好地解决结果被覆盖的问题。
在这里插入图片描述

DMA的介绍

在这里插入图片描述
在这里插入图片描述
  重点:用于高速搬运数据,还无需CPU干预。 因此在多通道采集模拟量是,我们可以建立一个数组,用于储存AD转换的数据。一旦ADC_DR寄存器里有了新的数据,就把新数据放在数组里。一会儿ADC_DR有了一个新的数据,就放在数组下一位。数组装满以后?根据需求来。我们设置的是循环模式,也就是再来一遍,覆盖之前的数据。

使用CubeMX配置DMA+多通道ADC

  我使用的板子,有两路NTC热敏电阻分别接在PC0与PC1上,我们把这两个引脚用作ADC1的通道10与11。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

启用DMA

  新建AD.c与AD.h文件,设置全局的接收数组与计数器。

//AD.c
uint32_t AD_Buf[ADC_CHANNEL_CNT];
uint32_t DMA_CNT = 0;

//AD.h
#define ADC_CHANNEL_CNT     2

extern uint32_t AD_Buf[ADC_CHANNEL_CNT];
extern uint32_t DMA_CNT;

  在主函数中可以借助HAL库提供的HAL_ADC_Start_DMA()函数,开启ADC的DMA功能,指定接收数组为AD_Buf,并指定接收的字符数为ADC_CHANNEL_CNT。

  DMA通常用于处理大量数据,但是目前,每秒发送两个数据,数据量很小,没有体现出DMA的特点。虽然只打印了两个数据,但是DMA到底采集了多少数据?已知DMA在AD转换完成以后“搬运”数据,所以我们可以在ADC转化完成的中断函数里做计数。

//AD.c
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  if(hadc==(&hadc1))
  {
    DMA_CNT++;
  }    
}
//main.c main()
  while (1)
  {
    HAL_Delay(1000);
    for(int i=0;i<ADC_CHANNEL_CNT;i++)
    printf("CH%d value = %d \n",i,AD_Buf[i]&0xFFF);
    printf("DMA采集数据的次数是 %d",DMA_CNT);
    DMA_CNT=0;
  }

  我看到的现象是,DMA_CNT大约是15W,每次两个数据,也就是DMA1秒钟搬运了30W个字节。可以想象,如果不是AD转换速度限制,DMA还可以更快一点.
  至于采集过来的AD值到底怎么用,那就是另一个问题了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章