最近项目又遇到了电池电压采集,锂电池的电压范围是4.2到2.8一般,当锂电池低于3.3V时,单片机供电电压会小于3.3V,那么电池电压参考计算4096就不能对应3.3,所以必须采用内部参考电压。(我项目中用到的是RP104N331 LDO,实际上当电池电压在3.5V左右时,LDO输出就已经不是3.3V,严重影响精度)

VREFINT_CAL = *(__IO uint16_t *)(0X1FF80078);

首先需要从数据手册知道VREFINT_CAL 的地址信息,读出16的值,所以这里采用了 uint16_t
同时stm32 开启两路ADC,一路是要采集的ADC,一路是内部参考电压

 ADC_ChannelConfTypeDef sConfig = {0};VREFINT_CAL = *(__IO uint16_t *)(0X1FF80078);V_temp1 = 3.3 / 4096 * (float)ADC_buffer[0] / 0.6;VDDA = 3 * VREFINT_CAL/(float)ADC_buffer[1];V_temp2 = VDDA/4096 * (float)ADC_buffer[0] / 0.6;printf("VDDA %f \r\n",VDDA);printf("%f V %f V\r\n",V_temp1,V_temp2);printf("%d %d\r\n",ADC_buffer[0],ADC_buffer[1]);

V1是常规的3.3V作为参考电压,VDDA可以通过VREFINT_CAL 计算得出,V_temp2是以VDDA得出,经过开关电源测试,V_temp2误差基本保持在0.01V

由于我们采集双通道,所以采用DMA传输

这里有几个参数需要注意,一个是ClockPrescaler,我这里采用ADC_CLOCK_ASYNC_DIV128,分频不同居然采集的电压不同,而且误差极大,这里一直找不到相关原因,另一个是LowPowerFrequencyMode,由于这里分频比较大,导致采用时钟很低,所以ENABLE,具体低于多少打开手册有要求,但是实测使能或者不使能差别并不是很大,最后在初始化完成之后需要增加校准函数HAL_ADCEx_Calibration_Start

下面是adc.c源码,这里的DMA是连续采集,只需在主函数开启一次HAL_ADC_Start_DMA(&hadc, (uint32_t *)ADC_buffer, 2)

/********************************************************************************* File Name          : ADC.c* Description        : This file provides code for the configuration*                      of the ADC instances.******************************************************************************* @attention** <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.* All rights reserved.</center></h2>** This software component is licensed by ST under BSD 3-Clause license,* the "License"; You may not use this file except in compliance with the* License. You may obtain a copy of the License at:*                        opensource.org/licenses/BSD-3-Clause********************************************************************************//* Includes ------------------------------------------------------------------*/
#include "adc.h"/* USER CODE BEGIN 0 */
__IO uint32_t uwADCxConvertedValue1 = 0;
__IO uint32_t uwADCxConvertedValue2 = 0;
__IO uint16_t VREFINT_CAL ;
float V_temp1,V_temp2,VDDA;
extern uint32_t ADC_buffer[2];
/* USER CODE END 0 */ADC_HandleTypeDef hadc;
DMA_HandleTypeDef hdma_adc;/* ADC init function */
void MX_ADC_Init(void)
{ADC_ChannelConfTypeDef sConfig = {0};/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion) */hadc.Instance = ADC1;hadc.Init.OversamplingMode = DISABLE;hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV128;hadc.Init.Resolution = ADC_RESOLUTION_12B;hadc.Init.SamplingTime = ADC_SAMPLETIME_12CYCLES_5;hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;hadc.Init.ContinuousConvMode = ENABLE;hadc.Init.DiscontinuousConvMode = DISABLE;hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;hadc.Init.DMAContinuousRequests = ENABLE;hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;hadc.Init.LowPowerAutoWait = DISABLE;hadc.Init.LowPowerFrequencyMode = ENABLE;hadc.Init.LowPowerAutoPowerOff = DISABLE;if (HAL_ADC_Init(&hadc) != HAL_OK){Error_Handler();}if (HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED) !=  HAL_OK){Error_Handler();}/** Configure for the selected ADC regular channel to be converted. */sConfig.Channel = ADC_CHANNEL_1;sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK){Error_Handler();}/** Configure for the selected ADC regular channel to be converted. */sConfig.Channel = ADC_CHANNEL_VREFINT;if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK){Error_Handler();}}void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(adcHandle->Instance==ADC1){/* USER CODE BEGIN ADC1_MspInit 0 *//* USER CODE END ADC1_MspInit 0 *//* ADC1 clock enable */__HAL_RCC_ADC1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/**ADC GPIO Configuration    PA1     ------> ADC_IN1 */GPIO_InitStruct.Pin = GPIO_PIN_1;GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* ADC1 DMA Init *//* ADC Init */hdma_adc.Instance = DMA1_Channel1;hdma_adc.Init.Request = DMA_REQUEST_0;hdma_adc.Init.Direction = DMA_PERIPH_TO_MEMORY;hdma_adc.Init.PeriphInc = DMA_PINC_DISABLE;hdma_adc.Init.MemInc = DMA_MINC_ENABLE;hdma_adc.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;hdma_adc.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;hdma_adc.Init.Mode = DMA_CIRCULAR;hdma_adc.Init.Priority = DMA_PRIORITY_LOW;if (HAL_DMA_Init(&hdma_adc) != HAL_OK){Error_Handler();}__HAL_LINKDMA(adcHandle,DMA_Handle,hdma_adc);/* USER CODE BEGIN ADC1_MspInit 1 */
//      if (HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED) !=  HAL_OK)
//      {
//    Error_Handler();
//      }/* USER CODE END ADC1_MspInit 1 */}
}void HAL_ADC_MspDeInit(ADC_HandleTypeDef* adcHandle)
{if(adcHandle->Instance==ADC1){/* USER CODE BEGIN ADC1_MspDeInit 0 *//* USER CODE END ADC1_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_ADC1_CLK_DISABLE();/**ADC GPIO Configuration    PA1     ------> ADC_IN1 */HAL_GPIO_DeInit(GPIOA, GPIO_PIN_1);/* ADC1 DMA DeInit */HAL_DMA_DeInit(adcHandle->DMA_Handle);/* USER CODE BEGIN ADC1_MspDeInit 1 *//* USER CODE END ADC1_MspDeInit 1 */}
} /* USER CODE BEGIN 1 */
void Acquisition_voltage()
{//float VDDA;ADC_ChannelConfTypeDef sConfig = {0};VREFINT_CAL = *(__IO uint16_t *)(0X1FF80078);V_temp1 = 3.3 / 4096 * (float)ADC_buffer[0] / 0.6;VDDA = 3 * VREFINT_CAL/(float)ADC_buffer[1];V_temp2 = VDDA/4096 * (float)ADC_buffer[0] / 0.6;printf("VDDA %f \r\n",VDDA);printf("%f V %f V\r\n",V_temp1,V_temp2);printf("%d %d\r\n",ADC_buffer[0],ADC_buffer[1]);//    //printf("VREFINT_CAL %d \r\n",VREFINT_CAL);sConfig.Channel = ADC_CHANNEL_1;sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK){Error_Handler();}
//
//
//  if (HAL_ADC_Start(&hadc) != HAL_OK)
//  {
//    /* Start Conversation Error */
//    Error_Handler();
//  }
//
//   HAL_ADC_PollForConversion(&hadc, 1000);
//
//  /* Check if the continous conversion of regular channel is finished */
//  if ((HAL_ADC_GetState(&hadc) & HAL_ADC_STATE_REG_EOC) == HAL_ADC_STATE_REG_EOC)
//  {
//      /*##-6- Get the converted value of regular channel  ########################*/
//      uwADCxConvertedValue1 = HAL_ADC_GetValue(&hadc);
//
//  }
//  printf("uwADCxConvertedValue1 %d\r\n",uwADCxConvertedValue1);
//  V_temp = 3.3 / 4096 * uwADCxConvertedValue1 / 0.6;
//  printf("V_temp %f V\r\n",V_temp);sConfig.Channel = ADC_CHANNEL_17;sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK){Error_Handler();}
//
//
//  if (HAL_ADC_Start(&hadc) != HAL_OK)
//  {
//    /* Start Conversation Error */
//    Error_Handler();
//  }
//
//   HAL_ADC_PollForConversion(&hadc, 1000);
//
//  /* Check if the continous conversion of regular channel is finished */
//  if ((HAL_ADC_GetState(&hadc) & HAL_ADC_STATE_REG_EOC) == HAL_ADC_STATE_REG_EOC)
//  {
//      /*##-6- Get the converted value of regular channel  ########################*/
//      uwADCxConvertedValue2 = HAL_ADC_GetValue(&hadc);
//  }
//
//  printf("uwADCxConvertedValue2 %d\r\n",uwADCxConvertedValue2);}
/* USER CODE END 1 *//************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

STM32内部参考电压+DMA精准采集电池电压相关推荐

  1. STM32使用内部参考电压提高ADC采集准确度

    我们在使用ADC采集外部电压时,一般默认参考电压为MCU的供电电压,例如单片机供电电压为3.3V时,我们计算采集电压的公式为: 假设12位ADC 采集电压=(AD值/4096)*3.3: 但是如果因为 ...

  2. STM32内部参考电压的使用

    一.STM32的内部参照电压VREFINT和ADCx_IN17相连接,它的作用是相当于一个标准电压测量点(和MSP430不一样..),内部参照电压VREFINT只能出现在主ADC1中使用. 内部参照电 ...

  3. 带内部参考电压(VREFINT)校正的STM32 DMA 内置温度采集

    笔者今天来介绍一下STM32ADC内置温度的采集,重点是通过内置参考电压来避免ADC参考电压VDDA对温度ADC采集的影响. 1.STM32ADC简介   stm32F4系列ADC,逐次趋近型AD.1 ...

  4. 基于STM32HAL库ADC+DMA模式,高精度采集电池电量与芯片内部温度方法 (48脚 使用内部参考电压方案)

    目录 概述 1.原理图 2.在这先普及一下概念 3.通过查看STM32L0中文数据手册中301页,第14.10 小节 ,DataSheet 4.ADC通道转换模式的理解 5.STM32CubeMx工具 ...

  5. STM32 ADC采样使用内部参考电压

    整理也能进步!写得清楚才能理解更深. [问题背景] 在使用ADC时,通常的用法是Vref+接电源VDD3.3V,然后计算时直接用3.3V做参考电压,但是这种方法忽略了一些情况如供电电压有可能随外部一些 ...

  6. STM32/APM32 用DMA采集ADC1多通道--标准库

    本文使用的是APM32E103作为示例的, STM32F/E以及APM32F等系列同样适用. 一.ADC及其通道 ADC1:最多16个外部通道,2个内部通道.内部通道分别是温度传感器和参考电压 ①:温 ...

  7. stm32 精确电压测量法(内部参考电压)

    芯片型号:stm32l051c8(其它型号请参考datasheet,仅供参考) 使用ADC采集电压时若使用外部参考电压,如果外部电压变化,且低于正常LDO工作电压时,输出的电压将发生改变,导致基准电压 ...

  8. STM8L051之通过ADC1与DMA读取内部参考电压,求取VDD电源电压---库函数版

    stm8L051芯片内部的参考电压与电源电压有一定的关系, 这在芯片供电电压变化的情况下,测量外部ADC电压输入 提供一个确定的参考电压.这里提前厘清下:该内部参考 电压VREFINT 并非ADC 的 ...

  9. STM32使用ADC+DMA进行多通道模拟量采集 (踩坑及傻瓜式解析)

    STM32使用ADC+DMA进行多通道模拟量采集 (踩坑及通俗解析) ​ 利用STM32的片上外设可采集多个模拟量(如传感器数值),并在嵌入式程序中使用.如果只使用了一个通道,用时令ADC转换而后读取 ...

最新文章

  1. FFT对信噪比的增益计算
  2. 你多久没换过壁纸了?新年了,换一换吧!
  3. JAVA WEB知识总结之一--responserequest
  4. 笔记-中项案例题-2021年上-范围管理
  5. java gui 单选_java GUI编程(swing)之三swing单选框复选框组件
  6. java 蓝桥杯训练 数的统计
  7. 计算机设备安装属于劳务吗,​安装服务费属于劳务费吗
  8. java对象 引用 原理,java对象引用和对象值得行为
  9. using的一种用法
  10. python设置excel边框_用Python操作Excel电子表格?单元格边框如何设置?样式有哪些?...
  11. 你必须会的微服务之Hystrix熔断器
  12. 微软亚洲研究院2017年笔试编程题
  13. 百练2801解题报告---填词
  14. 关于ARM的22个常用概念--的确经典
  15. 天龙八部科举答题问题和答案(全6/8)
  16. 巴特勒船长-百年一遇的男人
  17. 2022-2028全球与中国锂电池隔膜市场现状及未来发展趋势
  18. 2022年卡塔尔世界杯的“科技与狠活”
  19. does not have write access to 'C:\WINDOWS\Microsoft.NET\Framework\v4.0.30319\Temporary ASP.NET File
  20. 瑞星2008正式版升级包 官方安装包

热门文章

  1. Java判断一个字符串中是否包含中文字符工具类
  2. APG(Accelerate Proximal Gradient)加速近端梯度算法 和 NAG(Nesterov accelerated gradient)优化器原理 (一)
  3. 我们逃离北上广,美国人逃离硅谷
  4. 如何选择适合的虚拟主机搭建博客
  5. guava 各个版本下载地址
  6. 电影《我家也有贝多芬》有感
  7. 鹤山市计算机速成班学校,鹤山市职业技术学校官网
  8. 焦虑没有什么,请别贩卖焦虑
  9. Phoenix 技术分享
  10. 在人工智能风口下,AI翻译也火了