5

我正在尝试在 STM32F042 微控制器上读取 VDDA。当 VDD 为 3.29V 时,我得到了意想不到的结果。我一定错过了一些基本的东西。

输出:

VREFINT=1917; VREFINT_CAL=1524; VDDA=2623 mV
VREFINT=1885; VREFINT_CAL=1524; VDDA=2668 mV
VREFINT=1913; VREFINT_CAL=1524; VDDA=2628 mV
VREFINT=1917; VREFINT_CAL=1524; VDDA=2623 mV
VREFINT=1917; VREFINT_CAL=1524; VDDA=2623 mV

adc_test.c:

#include <stdio.h>
#include "stm32f0xx.h"

#define VREFINT_CAL_ADDR                0x1FFFF7BA  /* datasheet p. 19 */
#define VREFINT_CAL ((uint16_t*) VREFINT_CAL_ADDR)

extern void initialise_monitor_handles(void);

int main(void)
{
    RCC->APB2ENR |= RCC_APB2ENR_ADC1EN;     /* enable ADC peripheral clock */
    RCC->CR2 |= RCC_CR2_HSI14ON;            /* start ADC HSI */
    while (!(RCC->CR2 & RCC_CR2_HSI14RDY)); /* wait for completion */
    /* calibration */
    ADC1->CR |= ADC_CR_ADCAL;               /* start ADc CALibration */
    while (ADC1->CR & ADC_CR_ADCAL);        /* wait for completion */
    ADC1->CR |= ADC_CR_ADEN;                /* ADc ENable */
    while (!(ADC1->ISR & ADC_ISR_ADRDY));   /* wait for completion */
    ADC1->SMPR |= ADC_SMPR1_SMPR_0 |        /* sampling mode: longest */
      ADC_SMPR1_SMPR_1 |
      ADC_SMPR1_SMPR_2;
    /* VDD reference */
    ADC->CCR |= ADC_CCR_VREFEN;             /* VREF Enable */
    ADC1->CHSELR = ADC_CHSELR_CHSEL17;      /* CH17 = VREFINT */

    initialise_monitor_handles();           /* enable semihosting */

    while (1) {
        ADC1->CR |= ADC_CR_ADSTART;             /* start ADC conversion */
        while (!(ADC1->ISR & ADC_ISR_EOC));     /* wait for completion */
        uint32_t vdda = 3300UL * *VREFINT_CAL / ADC1->DR; /* ref. manual p. 252; constant and result in millivolts */
        printf("VREFINT=%lu; VREFINT_CAL=%lu; VDDA=%lu mV\n",
                (unsigned long)ADC1->DR,
                (unsigned long)*VREFINT_CAL,
                (unsigned long)vdda);
    }
}

数据表截图:

在此处输入图像描述

参考手册截图

请注意这是指 0.3V,但我认为这是一个错字,因为上面的数据表和下面较长的公式指的是 3.3V,并且 .3V 低于这部分的最低工作电压

在此处输入图像描述

4

3 回答 3

1

正如@Artur所说Vref +不是Vdda,但通常(这就是我在硬件设计中的方式)Vref +连接到Vdda(根据数据表使用相应的滤波器),因此计算Vdda与计算Vref +相同.

我将向您展示如何计算 vdda,因为我有它基于 STM32L431。

. 您必须首先配置 ADC 以测量 VREFINT:

void MX_ADC1_Init(void)
{

    /* USER CODE BEGIN ADC1_Init 0 */

    /* USER CODE END ADC1_Init 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_SYNC_PCLK_DIV4;
    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 = DISABLE;
    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 Regular Channel
     */
    sConfig.Channel = ADC_CHANNEL_VREFINT;
    sConfig.Rank = ADC_REGULAR_RANK_1;
    sConfig.SamplingTime = ADC_SAMPLETIME_247CYCLES_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 */
}

. 现在我将向您展示执行方程式的代码:

vdda = 3.0 * (VREFINT_CAL /average);
vch = VREF * (average / ADC_RESOLUTION);

log("vdd = %.5f - ", vdda);
log("vchn = %.5f", vch);

在哪里:

#define ADC_RESOLUTION 4095.0           // adc resolution 12 bits
#define VREFINT_CAL 1655.00             // Raw data acquired at a temperature of 30 °C (± 5 °C), VDDA = VREF+ = 3.0 V (± 10 mV)
#define VREF 3.3                        // voltage reference 3.3V

笔记:

“平均”是 adc 采集的 256 个样本的平均值(它只是一个简单的过滤器)。

'log' 是我创建的一个函数,类似于 uart 的 printf。

“VREFINT_CAL”因型号而异。

结果:

vdd = 3.28035 - vchn = 1.21343

正如我们所见,VREFINT 与数据表匹配(典型值为 1.212V):

VREFINT

于 2021-06-01T13:00:01.113 回答
1

我目前正在为 STM32L4 开发 ADC 驱动程序。在实施过程中,我遇到了几乎相同的问题。我认为第一个公式 在此处输入图像描述

不是计算 VDDA,而是 VREF+。这是 ADC 评估 ADC-IN 通道所依据的电压。此外,VREFINT_DATA 不是测量的 VREF+ 电压,而是取决于控制器的内部参考电压。就我而言,它在控制器数据表中定义: 在此处输入图像描述

这是我如何使用发布的公式的图片: 在此处输入图像描述

一些评论:ln 102:计算 VREF+ 而不是 VDDA

ln 105-110:计算所有等级/配置的序列

ln 108:计算 ADCpin_x 测量的电压

ln 109:乘以增益得到实际值

在我看来,通过计算每个转换序列的 VREF+,我会得到更好的结果,因为 VREF+ 上的一些波纹得到了补偿。

于 2020-10-13T14:04:28.350 回答
0

实际上是计算Vdda,由于Vref计算很简单,所以你必须读取ADC的相应通道,采样时间比数据手册中标注的时间长(通常为10 us)。如果 Vdda 为 2.0 V,则 4095 的值对应于 2.0(或更高)V 绝对值(相关 GND)。以线性方式,Vref 的值会比用 Vdda = 3.30 V 读取的值高得多。因此,有必要对用 2.0 V 读取的值进行补偿,以了解电压的绝对值。 ADC 正在测量。如果不进行补偿,它们将是相对于 Vdda 在那一刻所具有的电压电平的值。此外,电源值达到,这将是有用的,以免超出微控制器的规格。

于 2021-02-20T12:14:07.340 回答