HAL库学习——ADC精度问题以及多通道采集

一、简介

      博主在使用ADC测量电池电压时,发现测出来的AD值转换为实际电压不匹配,偏差大,因此通过网上收集资料,最终得知ADC采集精度提升的方法。前半部分主要是涉及多通道电压值采集,CubeMx的配置以及代码实现,以采集ADC1通道0、通道8和内部基准电压为例。后半部分讲解使用内部基准电压计算精确度较高的电压值。

 

二、运行环境

  MCU: STM32L071CBT6

  配置工具:STM32CubeMx

  IDE:MDK5

 

三、CubeMx配置

时钟配置:

        使用RCC外部低速时钟。

HAL库学习——ADC精度问题以及多通道采集_第1张图片

ADC配置:

        开启ADC的通道0、通道8和内部电压通道。

HAL库学习——ADC精度问题以及多通道采集_第2张图片

         当使用多通道采集时,Discontinuous Conversion Mode(间断转换模式)要使能。

HAL库学习——ADC精度问题以及多通道采集_第3张图片

串口配置:

       博主所用的板子将LPUART1引出来当调试串口,用来打印ADC转换的AD值,以验证ADC转换成功,串口配置如下,波特率设为9600Bit/s,Word Length为8 Bit,其余设置不变。

HAL库学习——ADC精度问题以及多通道采集_第4张图片

 

四、代码实现

       上述配置完生成代码如下:

     HAL库学习——ADC精度问题以及多通道采集_第5张图片

printf函数映射

#include 

//printf函数映射
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&hlpuart1, (uint8_t *)&ch, 1, 0xffff);
  return ch;
}

       为了使ADC采集值更准确,在ADC初始化完后使用HAL库函数HAL_ADCEx_Calibration_Start做自校准。

MX_ADC_Init();
if (HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED) != HAL_OK)
{
  printf("校准失败\r\n");  
}

   采集数据并打印

  uint8_t i;
  uint16_t adValue[3];

  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    for (i = 0; i < 3; i ++)
    {
      if (HAL_ADC_Start(&hadc) != HAL_OK)
      {
        printf("ADC开启失败\r\n");
      }
      
      if (HAL_ADC_PollForConversion(&hadc, 10) != HAL_OK)//等待转换完成,第二个参数表示超时时间,单位ms 
      {
        printf("ADC转换失败\r\n");
      }
      
      if (HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc), HAL_ADC_STATE_REG_EOC))
      {
        adValue[i] = HAL_ADC_GetValue(&hadc);
        printf("通道[%d]:%d\r\n", i, adValue[i]);
      }
    }

    
    HAL_ADC_Stop(&hadc);
    HAL_Delay(1000);
    
  }

串口助手输出如下

HAL库学习——ADC精度问题以及多通道采集_第6张图片

       通道[0]对应的为配置里的IN0,通道[1]对应的为配置里的IN8,通道[2]对应的为配置里的内部电压通道。由于通道[0]没有接任何输入电压,所以其采出来的AD值近乎为0,通道[1]通过外部做了1/2分压所以其采集出来的AD值为2326,通道[2]采集的是内部参考电压实际值,从数据手册可以得知内部参考电压的校准值存于地址0X1FF80078。

HAL库学习——ADC精度问题以及多通道采集_第7张图片

可将其值读出来:

uint16_t VREFINT_CAL;

VREFINT_CAL = *(__IO uint16_t *)(0X1FF80078);
printf("VREFINT_CAL:%d\r\n",VREFINT_CAL);

HAL库学习——ADC精度问题以及多通道采集_第8张图片

VREFINT_CAL = 1674,该值是在25°C,输入电压为3V情况下得到得,实际板子供电电压并不是如此,因此得出来会有误差,但基本接近。通道1的电压是博主自己给的,通过万用表测量得实际电压为1.71V。而理论代入公式应为:

(通道[1]AD值 / 4096) * 3.3V = (2297 / 4096) * 3.3 = 1.85V

跟实际差太多。通过查阅资料得知,为了更准确的获得采集的电压,需要使用内部参考电压计算实际的供电电压,将电源相关的 ADC 测量值转换为绝对电压值。具体计算公式在参考手册中:

HAL库学习——ADC精度问题以及多通道采集_第9张图片

      VREFINT_CAL即为内部参考电压的校准值为1674,ADC_DATAx即为通道[1]测出来的AD值,VREFINT_DATA为内部参考电压实际值,即为通道[2]的值。所使用的单片机ADC分辨率为12位所以FULL_SCALE的值为4095。将上述值代入公式,用代码实现如下:

float realVol;

realVol = (float)(3 * VREFINT_CAL * adValue[1]) / (adValue[2] * 4095)
printf("V = %.4f\r\n", realVol);

HAL库学习——ADC精度问题以及多通道采集_第10张图片

        最终得出的电压值在1.71V左右浮动,因此通过此方法可以测量出更精确的电压值。

你可能感兴趣的:(STM32)