打印

STM32如何通过内部VREF得到实际的VDDA值

[复制链接]
1030|7
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wangjiahao88|  楼主 | 2017-11-15 14:14 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我们经常会使用STM32 ADC功能测试外部电压,在一些精度不高的场合,我们一般就用3.3V作为参考电压来计算测到的电压值。不过,这种情况很少见,可能只有单片机学习板才会这样使用。因为我们使用的3.3V稳压芯片,很少有标准的3.300V输出,有可能是3.270V,也可能是3.345V,而且,还存在个体差异,这个板子上的电压是3.294V,另外一个板子上面,就可能是3.312V。如果我们都用3.300来计算的话,同样的电压,测出来的结果就会存在mV级别的差异。
在实际使用中,我们一般使用外部基准电压芯片,例如,100脚的STM32一般都有VREF引脚,就是用来接外部基准电压芯片,例如REF3133,输出的电压是标准的3.300V。

相关帖子

沙发
wangjiahao88|  楼主 | 2017-11-15 14:14 | 只看该作者
为什么不用基准电压芯片作为电源供电芯片?
因为基准电压芯片的输出电流都是小于25mA的,对于一般的电路板应用,这么点输出电流不足以让电路板工作。

使用特权

评论回复
板凳
wangjiahao88|  楼主 | 2017-11-15 14:15 | 只看该作者
不同的STM32 如何使用基准电压芯片?
对于100脚及其以上的芯片,把基准电压芯片连接到VREF芯片即可。
对于100脚以下的芯片,STM32没有把VREF引脚引出来,所以,我们只能把基准电压芯片连接到VDDA引脚。注意,STM32单片机上面有好多电源引脚,其中有若干VDD引脚,只有一个VDDA引脚,VDDA引脚就是模拟供电引脚。不过,需要注意,VDDA的电压不是随便定义的。例如,STM32F051系列单片机就规定,VDDA必须要大于或者等于VDD才可以正常工作,所以这时候,最好是给单片机3.0V供电,再给VDDA采用一个3.3V的基准电压芯片供电。
0.png

使用特权

评论回复
地板
wangjiahao88|  楼主 | 2017-11-15 14:16 | 只看该作者
不用电压基准电压芯片可以吗?
如果在你的应用中,VDDA引脚和VDD引脚连在一起,都是由电源芯片供电,这时候,如果你能知道VDDA的实际电压,也可以得到精确的ADC结果。例如,你可以用万用表测到VDDA电压,例如,是3.286V,你就可以使用3286来计算。不过,这也只能是在实验的时候,在实际使用中,如果你做了1万个板子,然后需要用万用表量1万个板子的电源电压,然后再给每个板子修改程序,显示是不可能的。
所以,STM32给我们又一个解决方案,STM32在内部都有一个参考电压引脚,可以通过配置,把这个脚连接到ADC输入引脚,是内部连接。然后再计算实际的VDDA值。不过,STM32也存在个体差异,所以,它并没有在手册上给出我们这个参考电压是多大。而是用出厂时调教好的校准值和得到的参考电压值一起使用。

使用特权

评论回复
5
wangjiahao88|  楼主 | 2017-11-15 14:20 | 只看该作者
/**
  * @brief  ADC Configuration
  * @param  None
  * @retval None
  */
static void ADC_Config(void)
{
  ADC_InitTypeDef     ADC_InitStructure;
  GPIO_InitTypeDef    GPIO_InitStructure;
  
  /* GPIOC Periph clock enable */
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
  
  /* ADC1 Periph clock enable */
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
  
  /* Configure ADC Channel 0 as analog input */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
  GPIO_Init(GPIOA, &GPIO_InitStructure);
  
  /* ADCs DeInit */  
  ADC_DeInit(ADC1);
  
  /* Initialize ADC structure */
  ADC_StructInit(&ADC_InitStructure);
        ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
        ADC_Init(ADC1, &ADC_InitStructure);
       
        /* Convert the ADC1 Channel 0 with 239.5 Cycles as sampling time */
  ADC_ChannelConfig(ADC1, ADC_Channel_Vrefint , ADC_SampleTime_239_5Cycles);
        ADC_VrefintCmd(ENABLE);
       
  /* 得到基准电压校准值 */
        VREFINT_CAL = *(__IO uint16_t *)(0X1FFFF7BA);
       
        /* ADC Calibration */
  ADC_GetCalibrationFactor(ADC1);
       
        /* Enable the ADC peripheral */
  ADC_Cmd(ADC1, ENABLE);     
  
  /* Wait the ADRDY flag */
  while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADRDY));
  
  /* ADC1 regular Software Start Conv */
  ADC_StartOfConversion(ADC1);
}

使用特权

评论回复
6
wangjiahao88|  楼主 | 2017-11-15 14:21 | 只看该作者
// 主函数
int main(void)
{
        delay_ms(200);
        ADC_Config();
        UART1_Init();
       
        while(1)
        {
                VREFINT_DATA =ADC_GetConversionValue(ADC1);
                VDDA_VAL = (3.3*VREFINT_CAL)/VREFINT_DATA;
                printf("\n\rVDDA:%.3fV\n\r",VDDA_VAL);
                while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
                delay_ms(1000);
        }
}

使用特权

评论回复
7
wangjiahao88|  楼主 | 2017-11-15 14:21 | 只看该作者
关键代码已经贴上

使用特权

评论回复
8
wangjiahao88|  楼主 | 2017-11-15 14:28 | 只看该作者
程序工程附件

stm32f051计算VDDA测试程序.zip

1.47 MB

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

473

主题

7517

帖子

30

粉丝