CH32内部参考电压的使用

Posted wchmcu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CH32内部参考电压的使用相关的知识,希望对你有一定的参考价值。

一、CH32的内部参照电压VREFINT和ADCx_IN17相连接,它的作用是相当于一个标准电压测量点

 注:1)1.2V为典型值,每个芯片的内部参考电压出厂后均为确定值,可以使用3.3V的标准稳压源供电,开启ADC测量出内部通道17的转换数值,将其转化为电压,则此值为此芯片的确定不变的内部参考电压VREFINT(1.17-1.23V都正常,但大部分都非常接近1或等于.2V)。

2)内部参照电压VREFINT与参考电压不是一回事。ADC的参考电压都是通过VREF+提供的并作为ADC转换器的基准电压(内部与VCC相连,等于VCC)。一般情况下,这种办法只适合于当VREF+参考电压(其实也就是VCC电压)离散性实在太差的情况下使用,只要外部供电稳定,此种方法就显得多此一举了。

当我们使用的VREF+是直接取自用VCC电压时,当VCC电压波动比较大时或稳压性能比较差时,可以借用CH32的内部参照电压VREFINT校正测量精度。

以测量通道0的电压值为例,先读出内部参考电压的ADC测量结果,记为 Value_VREF;再读出要测量通道0的ADC转换结果,记为Value_ch0;则要测量通道0的电压为:Vch0 =  (Value_ch0/4095))*(4095*VREFINT/Value_VREF)

简化之后为Vch0 = Value_ch0*VREFINT/Value_VREF。

这种方法等于变相将内部参照电压VREFINT当成是ADC参考电压,也就是说,此时VREF参考电压的准确度已在此已对结果影响不大了,ADC的转换结果基本由VREFINT的精度决定。

 

使用 STM32L422 上的内部参考电压测量模拟值

【中文标题】使用 STM32L422 上的内部参考电压测量模拟值【英文标题】:Measure analog value using Internal reference voltage on STM32L422 【发布时间】:2021-12-28 08:57:55 【问题描述】:

我必须使用 STM32L422 中的内部参考电压来测量 adc 值。根据数据表 STM32L422 内部参考电压为 1.2 V。我启用了 CubeMX 的内部 Vref。 模拟输入是 1V,但我得到 0.58 V。这里有什么问题吗?

STM32L422 数据表显示内部 Vref = 1.2 V。当我测量 Vref 引脚时,它是 0.53 V。 这里有什么问题?

对于1V输入,使用20K、10K分压器获得,对于3V,获得的数字和模拟值如下: 数字:1983,模拟值:0.581099

#define VREFINT_ADDR      0x1FFF75AA      // VREF voltage
#define VREFINT         (*((uint16_t *) VREFINT_ADDR))

int main(void)

  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_ADC1_Init();
  MX_SPI1_Init();
  MX_USART1_UART_Init();
  MX_USART2_UART_Init();
  MX_TIM6_Init();
  MX_RTC_Init();

  /* USER CODE BEGIN 2 */

  printf("System Booting On! \n");

  printf("VREFINT: %ud\n", VREFINT);
  printf("ADC Calibration! \n");
  while(HAL_ADCEx_Calibration_Start(&hadc1,0) != HAL_OK);

  printf("Battery Voltage Check ...\n");

  HAL_Delay(100);   // 1000ms OK => 100ms OK
  HAL_ADC_Start(&hadc1);
  HAL_ADC_PollForConversion(&hadc1,100);
  ADC_Val=HAL_ADC_GetValue(&hadc1);
  HAL_ADC_Stop(&hadc1);
  
  float Result = (float)((1.200 * ADC_Val) / 4095);

  printf("****************************************************************\n");
  printf("Digital: %d, Analog value : %f\r\n", ADC_Val, Result);
  printf("****************************************************************\n");
    
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  
    ;     
  
  /* USER CODE END 3 */


void MX_ADC1_Init(void)


  /* USER CODE BEGIN ADC1_Init 0 */

  /* USER CODE END ADC1_Init 0 */

  ADC_MultiModeTypeDef multimode = 0;
  ADC_ChannelConfTypeDef sConfig = 0;

  /* USER CODE BEGIN ADC1_Init 1 */

  /* USER CODE END ADC1_Init 1 */
  /** Common config
  */
  hadc1.Instance = ADC1;
  hadc1.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV8;
  hadc1.Init.Resolution = ADC_RESOLUTION_12B;
  hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
  hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc1.Init.LowPowerAutoWait = DISABLE;
  hadc1.Init.ContinuousConvMode = ENABLE;
  hadc1.Init.NbrOfConversion = 1;
  hadc1.Init.DiscontinuousConvMode = DISABLE;
  hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc1.Init.DMAContinuousRequests = DISABLE;
  hadc1.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc1.Init.OversamplingMode = DISABLE;
  if (HAL_ADC_Init(&hadc1) != HAL_OK)
  
    Error_Handler();
  
  /** Configure the ADC multi-mode
  */
  multimode.Mode = ADC_MODE_INDEPENDENT;
  if (HAL_ADCEx_MultiModeConfigChannel(&hadc1, &multimode) != HAL_OK)
  
    Error_Handler();
  
  /** Configure Regular Channel
  */
  sConfig.Channel = ADC_CHANNEL_12;
  sConfig.Rank = ADC_REGULAR_RANK_1;
  sConfig.SamplingTime = ADC_SAMPLETIME_92CYCLES_5;
//    sConfig.SamplingTime = ADC_SAMPLETIME_640CYCLES_5;
  sConfig.SingleDiff = ADC_SINGLE_ENDED;
  sConfig.OffsetNumber = ADC_OFFSET_NONE;
  sConfig.Offset = 0;
  if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
  
    Error_Handler();
  
  /* USER CODE BEGIN ADC1_Init 2 */

  /* USER CODE END ADC1_Init 2 */


【问题讨论】:

【参考方案1】:

STM32 ADC 的工作方式与您想象的有点不同,Vrefint 的名称有点令人困惑。请务必阅读参考手册

Vrefint 不是 ADC 的参考电压。它只是连接其中一个通道。当您测量此电压时,您可以知道 ADC 的 Vref(在您的情况下是 Vdda)所以您使用的公式是错误的。

STM32L422 数据表说内部 Vref = 1.2 V

不要只阅读数据表参考手册

然后您需要测量您的 Vref (Vdda),然后您可以测量引脚上的电压。

【讨论】:

我对 VREFINT_CAL 和 VREFINT_DATA 感到困惑。我在想 VREFINT_CAL 是来自 VREFINT 寄存器( 0x1FFF75AA -0x1FFF75AB )的值。如何获取 VREFINT_DATA。你能简单解释一下这个过程吗? 你需要测量它。 Vrefint 只是普通的 ADC 通道 需要使用 Vrefint 计算 VDDA。为此,我没有设置 ADCx_CCR 的 VREFEN 位。我已经检查了 CubeMX 中的 Vrefint 通道,它一定已经完成了这项工作!。我将通道设置为 ADC_CHANNEL_VREFINT,然后将电压连接到 Vref 引脚。

以上是关于CH32内部参考电压的使用的主要内容,如果未能解决你的问题,请参考以下文章

使用 STM32L422 上的内部参考电压测量模拟值

STM32F103(十九)ADC相关的几个实验—内部温度传感器内部参照电压光敏传感器

STM32F103(十九)ADC相关的几个实验—内部温度传感器内部参照电压光敏传感器

CMT2380F32模块开发17-ADC例程

CMT2380F32模块开发17-ADC例程

CMT2380F32模块开发17-ADC例程