我正在尝试在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
#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 :(得分:1)
我目前正在为STM32L4开发ADC驱动器。在实施过程中,我遇到了几乎相同的问题。我认为第一个公式
不是计算VDDA,而是VREF +。 ADC用来评估ADC-IN通道的电压。 此外,VREFINT_DATA不是测量的VREF +电压,而是与控制器有关的内部基准电压。就我而言,它在控制器数据表中定义:
一些评论: ln 102:计算VREF +而不是VDDA
在105-110中:计算所有等级/配置的顺序
ln 108:计算ADCpin_x测得的电压
ln 109:乘以增益以获得实际值
我认为通过为每个转换序列计算VREF +,我会得到更好的结果,因为这样可以补偿VREF +上的一些纹波。
答案 1 :(得分: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
注意:
'average' 是 adc 采集的 256 个样本的平均值(它只是一个简单的过滤器)。
'log'是我为uart创建的一个类似于printf的函数。
“VREFINT_CAL”因型号而异。
结果:
vdd = 3.28035 - vchn = 1.21343
如我们所见,VREFINT 与数据表匹配(典型值为 1.212V):
答案 2 :(得分:0)
其实就是在计算Vdda,由于Vref的计算很简单,你要读取ADC对应的通道,采样时间比data sheet中标注的要长(一般是10us)。如果 Vdda 为 2.0 V,则 4095 的值对应于 2.0(或更多)V 绝对值(相关 GND)。以线性方式,Vref 的值将远高于在 Vdda = 3.30 V 时读取的值。因此,需要对用 2.0 V 读取的值进行补偿,以了解所读取的电压绝对值ADC 正在测量。如果它们没有得到补偿,它们将是相对于 Vdda 在那一刻的电压电平的值。 此外,还实现了电源值,这将有助于不超出微控制器的规格。