HAL库配置ADC_1_单通道配置


一、ADC概念

1.ADC特点—以STM32F4x系列为例

💦在使用ADC外设前,先查看下芯片手册,看下ADC的特点。

在这里插入图片描述

2.ADC引脚介绍—以STM32F4x系列为例

💦ADC的使用,一定是有参考电压的,在使用时要注意,芯片手册上关于ADC参考电压的范围。
通常正参考电压VREF+连接到VCC,负参考电压VREF-连接到GND

在这里插入图片描述

3.ADC框图简介—以STM32F4x系列为例

💦通过框图可以了解ADC的工作流程。

在这里插入图片描述

4.ADC参数的简介

  下面是ADC比较常用的参数说明:

💦(1)测量范围:对于 ADC 来说测量范围就好比尺子的量程,需要采集的信号范围,不能超过 ADC 的测量范围(比如,STM32系列的 ADC 正常就不能超过3.3V)。
💦(2)分辨率:假如 ADC 的测量范围为 0-3.3V,分辨率设置为12位,分辨率就是最 > 💦低有效位(LSB)的对应输入电压值,分辨率 =3300/4095 ≈ 0.806mV。12位的2进制数最大可以表示4096,ADC采集就是将模拟信号量化为数字信号的过程,3300/4096就是将3.3V分成4096个份,每份电压为0.000805V。所以,分辨率越高,采集到的信号越精确,因此分辨率是衡量 ADC 的一个重要指标。
💦(3)采样时间:当 ADC 在某时刻采集外部电压信号的时候,此时外部的信号应该保持不变,但实际上外部的信号是不停变化的。所以在 ADC 内部有一个保持电路,保持某一时刻的外部信号,这样 ADC 就可以稳定采集了,保持这个信号的时间就是采样时间。
💦(4)采样率:也就是在一秒的时间内采集多少次。很明显,采样率越高越好,当采样率不够的时候可能会丢失部分信息,所以 ADC 采样率是衡量 ADC 性能的另一个重要指标。

5.采样时间和采样率的说明

💦ADC采样两点间隔的时间一定要大于ADC的采样时间

💦举例说明:
STM32F103一般将时钟配置主频为72M、APB2为72M。ADC挂在APB2时钟总线上,且ADC的时钟不能超过14M。所以一般将ADC的分频设置为6,ADC的时钟主频就为72/6=12MHz。那么一个周期就是:1/12MHz=0.0833us。

💦ADC转换时间 = 采样时间 + 12.5个周期

💦示例:
💦当ADC时钟主频为14MHz并且采样时间为1.5个周期时:采样时间 = 1.5 + 12.5 = 14个周期;一个周期的时间为1/14MHz,一共14个周期,1 / 14MHz * 14个周期 = 1us,
那么此时ADC的采样频率就是1/1us=1000KHz=1MHz,这也是理论上ADC的最大采样频率。

STM32F1系列的时钟主频一般设置为了12M,采样时间的设置所对应采样频率如下图所示:
在这里插入图片描述

💦从上图可以知道ADC的最小采样时间,当ADC时钟主频为12M并且采样时间为1.5个周期时,ADC采样两点的时间必须大于1.17us。
💦而STM32F031系列的ADC时钟主频为14MHz,采样时间的设置所对应采样频率如下图所示:

在这里插入图片描述

💦当ADC时钟主频为14M并且采样时间为1.5个周期时,ADC采样两点的时间必须大于1us。

💦举例说明:
💦确定采样率
  (1)如果我们的输入信号是 20KHz (周期为 50us),若要将它恢复出来,一个周期最少采样20个点,此时采样率要达到400KHz(两个点的时间间隔为2.5us),所以ADC的采样率必须在400KHz 以上。为了达到最好的精度,我们选取ADC时钟为12MHz,即6分频。在12MHz 以及保证采样率的情况下,采样时间越长其,准确性就越好。
  (2)可以计算 2.5us = (12.5 + 采样时间)/ 12MHz ,可以求得采样时间为17.5;所以采样时间的选择必须小于等于17.5个周期,才能保证采样率在400KHz 以上。所以我们可以选择1.5、7.5、13.5,为获得更高的精准度,我们可以选择13.5个周期。
切记采样点数必须达到要求。

二、ADC工作模式

💦1. 轮询模式
💦2. 中断模式
💦3. DMA模式

1.轮询模式

HAL库函数如下:

HAL_ADC_Start(ADC_HandleTypeDef* hadc);//轮询模式,需放在循环中不断开启
HAL_ADC_Stop(ADC_HandleTypeDef* hadc);
HAL_ADC_PollForConversion(ADC_HandleTypeDef* hadc, uint32_t Timeout); //等待转换结束,只适用于轮询,注意配置转换时间

2.中断模式

HAL库函数如下:


HAL_ADC_Start_IT(ADC_HandleTypeDef* hadc);//中断模式
HAL_ADC_Stop_IT(ADC_HandleTypeDef* hadc);
HAL_ADC_IRQHandler(ADC_HandleTypeDef* hadc);//中断

3.DMA模式

HAL库函数如下:

HAL_ADC_Start_DMA(ADC_HandleTypeDef* hadc, uint32_t* pData, uint32_t Length);//DMA模式
HAL_ADC_Stop_DMA(ADC_HandleTypeDef* hadc); 
HAL_ADC_GetValue(ADC_HandleTypeDef* hadc); //读取ADC的值
HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc);//结束后回调
HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc);//转换过程中回调

三、ADC单通道采集-stm32Fx系列为例

1.轮询模式下单通道采集

STM32CubeMX配置
在这里插入图片描述
💦ADC模式选择
通常选择独立模式,在此模式下,ADC相互独立工作。在ADC_CDR寄存器中配置ADC的模式,详情如下。
在这里插入图片描述
💦ADC分频
用于设置ADC的工作频率。注意ADC的工作频率不能太高,根据实际情况进行选择。

💦ADC分辨率
在这里插入图片描述
💦ADC对齐方式
一般选择右对齐方式
💦ADC的扫描模式
扫描模式用于多通道转换,单通道的时候不适用。
在这里插入图片描述
💦ADC的连续转换模式
在连续转换模式下,ADC 结束一个转换后立即启动一个新的转换。
   在CUBE中选中ENABLE就是连续模式,DISABLE就是单次模式。开启连续模式后,ADC的转换不由其他控制。例如将ADC设置为了定时器的TGRO触发采样,如果开启连续模式,ADC将忽略定时器的触发采样。(连续转换模式开启后其实就是满频率的采样)。
💦ADC的间接转换模式(不连续模式)
通俗来讲_间断模式: 可以将多个通道进行分组采集,例如你开启了CH0~3这4个通道,假如你设置了间断次数为4,就相当于将4个通道分成了4组,每组1个通道,那么要想采集完这4个通道就需要手动触发4次ADC采集;如果设置了间断次数为2,那么采集完4个通道就需要手动触发2次ADC采集
在这里插入图片描述
💦ADC的DMA
用于开启DMA模式

2.轮询模式-单通道下采集代码示例

单通道-单次采集模式

在这里插入图片描述

//获得ADC值
//ch: 通道值 0~16,取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
//返回值:转换结果
uint16_t Get_Adc(uint32_t ch)   
{
    ADC_ChannelConfTypeDef ADC1_ChanConf;    
    ADC1_ChanConf.Channel=ch;                                   //通道
    ADC1_ChanConf.Rank=1;                                       //第1个序列,序列1
    ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_480CYCLES;        //采样时间
    ADC1_ChanConf.Offset=0;                 
    HAL_ADC_ConfigChannel(&hadc1,&ADC1_ChanConf);        //通道配置
    HAL_ADC_Start(&hadc1);                               //开启ADC	
    HAL_ADC_PollForConversion(&hadc1,10);                //轮询转换 
	return (uint16_t)HAL_ADC_GetValue(&hadc1);	        //返回最近一次ADC1规则组的转换结果
}
//获取指定通道的转换值,取times次,然后平均 
//times:获取次数
//返回值:通道ch的times次转换结果平均值
uint16_t Get_Adc_Average(uint32_t ch,uint8_t times)
{
	uint32_t temp_val=0;
	uint8_t t;
	for(t=0;t<times;t++)
	{
		temp_val+=Get_Adc(ch);
		HAL_Delay(5);
	}
	return temp_val/times;
}

int main(void)
{
  uint16_t adc_temp=0;
    float voltage_temp=0;
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  while (1)
  {    
      adc_temp=Get_Adc_Average(ADC_CHANNEL_0,20);
      voltage_temp=(float)adc_temp*(3.3/4096);
      printf("V:%f\n",voltage_temp);
  }
}

输入正弦信号,采集结果如下:
在这里插入图片描述

轮询模式,要在循环连续采集

单通道-连续采集模式

暂未实现,原因未知

3.中断模式-单通道下采集代码示例

单通道-单次采集模式

产生中断后回进入公共的中断服务函数,完成中断处理,中断服务函数最终会调用ADC转换完成回调函数,所以采集完成后在回调函数中处理。
在这里插入图片描述
在回调函数中,设置一个状态量,在主函数中对此状态量进行查询,当变量为1时,在进行数据的获取和处理。

uint8_t adc_state=0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if(hadc==&hadc1)
    {
     adc_state=1;     
    }
}

下面代码是单次采集模式,转换一次就结束转换,所以要在循环中,开启下一次转换。
所以要在循环中,开启下一次转换。

int main(void)
{
    uint16_t adc_temp=0,adc_cnt=0,temp=0;;
    float voltage_temp=0;
    uint32_t temp_val=0;
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
   HAL_ADC_Start_IT(&hadc1);
  while (1)
  { 
      extern uint8_t adc_state;
      if(adc_state==1)
      {
         adc_state=0;
          temp=HAL_ADC_GetValue(&hadc1);         
          temp_val+=temp;
          HAL_Delay(1);          
          adc_cnt++; 
          HAL_ADC_Start_IT(&hadc1); //开启下一次转换
            if(adc_cnt>=30)
          {  
              adc_temp=(uint16_t)(temp_val/adc_cnt);
              adc_cnt=0;
              temp_val=0;
              voltage_temp=(float)adc_temp*(3.3/4096);
              printf("V:%f\n",voltage_temp);
          }                          
      }            
  }
}

输入正弦信号,采集结果如下:
在这里插入图片描述

单通道-连续采集模式

将连续转换模式使能,即可开启连续采集模式。
在这里插入图片描述
与单次采集的区别是,开始转换函数HAL_ADC_Start_IT(&hadc1),在主函数初始化时,调用一次即可,开启连续转换。

int main(void)
{
    uint16_t adc_temp=0,adc_cnt=0,temp=0;;
    float voltage_temp=0;
    uint32_t temp_val=0;
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
   HAL_ADC_Start_IT(&hadc1);
  while (1)
  { 
      extern uint8_t adc_state;
      if(adc_state==1)
      {
         adc_state=0;
          temp=HAL_ADC_GetValue(&hadc1);         
          temp_val+=temp;
          HAL_Delay(1);          
          adc_cnt++; 
         // HAL_ADC_Start_IT(&hadc1); //开启下一次转换
            if(adc_cnt>=30)
          {  
              adc_temp=(uint16_t)(temp_val/adc_cnt);
              adc_cnt=0;
              temp_val=0;
              voltage_temp=(float)adc_temp*(3.3/4096);
              printf("V:%f\n",voltage_temp);
          }                          
      }            
  }
}

4.DMA模式-单通道下采集代码示例

单通道-单次采集模式

产生中断后回进入公共的中断服务函数,完成中断处理,中断服务函数最终会调用ADC转换完成回调函数,所以采集完成后在回调函数中处理。
在回调函数中,获取数据,可以在回调函数里将数据进行赋值,处理数据可以在主函数中处理,也可以在回调中处理。

   uint16_t adc_dma_temp=0;
    uint8_t adc_dma_cnt=0;
    uint32_t adc_dma_sum=0;
   float voltage_temp=0;
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
    if(hadc==&hadc1)
    {       
          adc_dma_sum+=adc_dma_temp;
          HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&adc_dma_temp, 1);//获取数据后,开启下次转换
          adc_dma_cnt++;
          if(adc_dma_cnt>=20)
          {
              adc_dma_temp=(uint16_t)(adc_dma_sum/adc_dma_cnt);
              voltage_temp=(float)adc_dma_temp*(3.3/4096);
              printf("V:%f\n",voltage_temp);
              adc_dma_cnt=0;
              adc_dma_sum=0;             
           }    
    }
}
int main(void)
{
  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_ADC1_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  extern uint16_t adc_dma_temp;
  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&adc_dma_temp, 1);//开启一次,让其进入中断

  while (1)
  {
      HAL_Delay(5);
  }

}

单通道-连续采集模式

暂未成功

  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值