读取STM32芯片温度与当前供电电压

c8bf2cf8df839fb8fe9fa7bebf02c6fa.png

在做低功耗产品的时候读取芯片温度和当前电压是十分重要的一件事情。通过当前供电电压可以知晓电池电量是否低于水平值实现电池缺电报警。读取芯片温度也很重要,可以在使用内部振荡器的时候通过校准算法根据温度变化来实现实时校准芯片。

如果不使用或尽量少使用外部元器件来实现这两个功能是摆在我们面前一个很重要的事情,遗憾的是现在网上的资料非常混乱,基本上直接使用总有点那么别扭。

如何读取芯片电压?当然肯定是需要用ADC了。不过这个时候需要有一个参考电压作为比对,很多人提出在外面使用一组LDO实现参考电压,那样其实LDO本身也有一定能耗,在我们追求极致低消耗的时候也不适合。当然很多人说了为什么不使用PVD来做,那么我来说说,PVD本身是做电压曲线检测的,如果你要求低于2.5V就报警,你会发现如果你启动电压<2.5V的时候无法检测出来。所以还是自己做。还好STM32L0单片机在内部有一个核心电压,并且有一个寄存器VREFINT_CAL值可以用作基准参考从而计算出相当比较精准的电压。经过测量,误差还是基本满足电池供电检测的要求。

如何读取芯片温度?在STM32L0下,只要读到当前电压,配合温度寄存器,就可以取得当前温度了。当前温度误差比较大,即使高精度采样,为了节省运算时间,误差还是有3度的误差,因此这个地方需要宽泛一些。

#include "stm32l0xx_ll_adc.h" //需要这个库实现公式计算
//初始化
void init_adc1(void)
{
  ADC_ChannelConfTypeDef sConfig;


  hadc.Instance = ADC1;
  hadc.Init.OversamplingMode = DISABLE;
  hadc.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV1;
  hadc.Init.Resolution = ADC_RESOLUTION_12B;//ADC_RESOLUTION_12B;
  hadc.Init.SamplingTime = ADC_SAMPLETIME_160CYCLES_5; //160.5cycles如果低于39.5cycles温度采样精准度不够
  hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
  hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
  hadc.Init.ContinuousConvMode = DISABLE;
  hadc.Init.DiscontinuousConvMode = DISABLE;
  hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
  hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
  hadc.Init.DMAContinuousRequests = DISABLE;
  hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
  hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
  hadc.Init.LowPowerAutoWait = DISABLE;
  hadc.Init.LowPowerFrequencyMode = DISABLE;
  hadc.Init.LowPowerAutoPowerOff = DISABLE;
  
  if (HAL_ADC_Init(&hadc) != HAL_OK)
    {
      _Error_Handler(__FILE__, __LINE__);
    }
/**Configure for the selected ADC regular channel to be converted. 
*/
  sConfig.Channel = ADC_CHANNEL_VREFINT; //初始化VREFINT_CAL参考电压
  sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
  
  sConfig.Channel = ADC_CHANNEL_TEMPSENSOR; //初始化芯片温度传感器
  sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
  if (HAL_ADC_ConfigChannel(&hadc, &sConfig) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
}
//读取adc1值
uint16_t readchannel_adc1(uint32_t Channel)
{
  ADC_ChannelConfTypeDef adcConf;
  uint16_t adcData = 0;
  
/* wait the the Vrefint used by adc is set */
  while (__HAL_PWR_GET_FLAG(PWR_FLAG_VREFINTRDY) == RESET) {};
//启动CLK时钟
  __HAL_RCC_ADC1_CLK_ENABLE();


/*calibrate ADC if any calibraiton hardware*/
  HAL_ADCEx_Calibration_Start(&hadc, ADC_SINGLE_ENDED );


/* Deselects all channels*/
  adcConf.Channel = ADC_CHANNEL_MASK;
  adcConf.Rank = ADC_RANK_NONE; 
  HAL_ADC_ConfigChannel( &hadc, &adcConf);


/* configure adc channel */
  adcConf.Channel = Channel;
  adcConf.Rank = ADC_RANK_CHANNEL_NUMBER;
  HAL_ADC_ConfigChannel( &hadc, &adcConf);




/* Start the conversion process */
  HAL_ADC_Start(&hadc);


/* Wait for the end of conversion */
  HAL_ADC_PollForConversion( &hadc, HAL_MAX_DELAY );


/* Get the converted value of regular channel */
  adcData += HAL_ADC_GetValue(&hadc);


  __HAL_ADC_DISABLE(&hadc);


  __HAL_RCC_ADC1_CLK_DISABLE();


  return adcData;
}
//具体调用代码
void main(void)
{
  init_adc1(); //完成初始化
  uint16_t vdda_mV = __LL_ADC_CALC_VREFANALOG_VOLTAGE(readchannel_adc1(ADC_CHANNEL_VREFINT),LL_ADC_RESOLUTION_12B); //取得当前VDDA的电压,单位mV
  uint16_t temp_degress = __LL_ADC_CALC_TEMPERATURE(vdda_mV,readchannel_adc1(ADC_CHANNEL_TEMPSENSOR),LL_ADC_RESOLUTION_12B); //取得当前的温度,单位摄氏度
}

==========

往期回顾:

C语言求数组长度的5种方法

寄存器开发,HAL开发和LL开发的区别

对应届大学生找工作的建议

把一个MOS管制作成开关电路

==========

f78c691478b51550a46525ff6422fb56.png

46460152eb7469626fca5a1f0bdf02bb.png

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值