STM32开发(十二)STM32F103 功能应用 —— NTC 温度采集


一、基础知识点

了解STM32 片内资源ADC。本实验是基于STM32F103开发 实现 NTC温度采集。

NTC温度采集实现:
1、使用查表方式。可参考热敏电阻采集温度 NTC 温度表(通用)
2、使用简单通用公式实现热敏电阻与温度之间的转换。

本章通过第二种方式来了解下STM32 ADC的使用以及分析NTC采集数值误差的产生。
准备好了吗?开始我的show time。


二、开发环境

1、硬件开发准备
主控:STM32F103ZET6
热敏电阻NTC:SDNT2012X103F3950FTF
在这里插入图片描述
2、软件开发准备
软件开发使用虚拟机 + VScode + STM32Cube 开发STM32,在虚拟机中直接完成编译下载。
该部分可参考:软件开发环境构建


三、STM32CubeMX相关配置

1、STM32CubeMX基本配置
本实验基于CubeMX详解构建基本框架 进行开发。

2、STM32CubeMX NTC 相关配置
(1) 数值量采集(ADC)
在这里插入图片描述
2、时钟配置(ADC的输入时钟不得超过14MHz)
在这里插入图片描述


四、Vscode代码讲解(过程中相关问题点在第五点中做解释说明)

1、定义NTC相关的结构体以及相关宏定义

#define VREFINT               3.3          // reference voltage
#define ADC_Resolution_Ratio  4096         // ADC Resolution Ratio
#define Beta                  3950         // B value
#define AT                    298.15       // absolute temperature    TN(k)=273.15+TN(℃)
#define V_Sample              3.3          // sample voltage
#define R_Ref                 10           // Reference resistance

typedef struct NTC_s
{
    
    
  uint16_t  uADC_Value;            		// ADC采集的数字量
  double    fTemperature;          		// 温度
  double    fVoltage;              		// 电压模拟量
  double    fRt;                   		// 热敏电阻值
  void (*ADC_Get_Temperature)(void);    // 获取温度函数
} NTC_t;

NTC_t NTC = {
    
    
  0,
  0.0,
  0.0,
  0.0,
  ADC_Get_Temperature
};

(1)Beta值如何确定?
(2)基准电压与采样电压有何区别?

2、获取温度值函数具体实现

void ADC_Get_Value(void)
{
    
    
  uint32_t value;
  uint32_t rt_value;

	// 1、ADC校准
  HAL_ADCEx_Calibration_Start(&hadc1);
  
	// 2、启动 A/D转换
  HAL_ADC_Start(&hadc1);

	// 3、等待转换完成
  if(HAL_ADC_PollForConversion(&hadc1, 10) == HAL_OK)
  {
    
    
  	// 4、获取在当前ADC采样值
    NTC.uADC_Value = HAL_ADC_GetValue(&hadc1);

	// 计算公式:(1)获取电压模拟量
    NTC.fVoltage = (NTC.uADC_Value*VREFINT)/ADC_Resolution_Ratio;
    value = (NTC.fVoltage-(uint32_t)NTC.fVoltage)*100;
	// 计算公式:(2)获取热敏电阻值
    NTC.fRt =  (NTC.fVoltage*10)/(V_Sample-NTC.fVoltage);
    rt_value = (NTC.fRt-(uint32_t)NTC.fRt)*100;

    printf(" ADC采集值  : %d \n\r",      NTC.uADC_Value);
    printf(" 电压模拟量 : %ld.%ld V \n\r", (uint32_t)NTC.fVoltage, value);
    printf(" NTC电阻值  : %ld.%ld KΩ \n\r", (uint32_t)NTC.fRt, rt_value);
  }
  else
  {
    
    
  	// 转换失败,超时打印
    printf(" ADC Get Value Failue. Timeout. \n\r");
  }
  HAL_ADC_Stop(&hadc1);
}

static void ADC_Get_Temperature(void)
{
    
    
  int32_t value;
  ADC_Get_Value();
  // 计算公式:(3)获取当前温度值
  NTC.fTemperature = ((double)Beta*(double)AT)/(((double)AT*log(NTC.fRt/(double)R_Ref)+(double)Beta))-273.15;
  value = (NTC.fTemperature-(uint32_t)NTC.fTemperature)*100;
  printf(" 温度 = %ld.%ld ℃ \n\r ",(uint32_t)NTC.fTemperature, value);
}

(3)公式详解
(4)误差存在哪些方面?

3、ADC校准代码解析

HAL_StatusTypeDef HAL_ADCEx_Calibration_Start(ADC_HandleTypeDef* hadc)
{
    
    
  HAL_StatusTypeDef tmp_hal_status = HAL_OK;
  uint32_t tickstart;
  __IO uint32_t wait_loop_index = 0U;
  
  /* 检查参数 */
  assert_param(IS_ADC_ALL_INSTANCE(hadc->Instance));

  /* Process locked */
  __HAL_LOCK(hadc);
    
  // 1、ADC使能前,必须在disable模式下
  // 2、关闭ADC至少两个时钟周期
  // 在常规组和注入组上停止电位转换
  // 关闭ADC外围
  tmp_hal_status = ADC_ConversionStop_Disable(hadc);
  
  /* 检查ADC当前是否有效 */
  if (tmp_hal_status == HAL_OK)
  {
    
    
    /* 设置ADC状态 */
    ADC_STATE_CLR_SET(hadc->State,
                      HAL_ADC_STATE_REG_BUSY | HAL_ADC_STATE_INJ_BUSY,
                      HAL_ADC_STATE_BUSY_INTERNAL);
    
   /*硬件条件:开始校准前延迟。* /
   /* 计算与ADC时钟周期对应的CPU时钟周期。* /
   /*—等待预期的ADC时钟周期延迟*/
    wait_loop_index = ((SystemCoreClock
                        / HAL_RCCEx_GetPeriphCLKFreq(RCC_PERIPHCLK_ADC))
                       * ADC_PRECALIBRATION_DELAY_ADCCLOCKCYCLES        );

    while(wait_loop_index != 0U)
    {
    
    
      wait_loop_index--;
    }
    
    /* 2. 使能ADC */
    ADC_Enable(hadc);
    
    /* 3。复位ADC校准寄存器*/
    SET_BIT(hadc->Instance->CR2, ADC_CR2_RSTCAL);
    
    tickstart = HAL_GetTick();  

   /*等待校准重置完成*/
    while(HAL_IS_BIT_SET(hadc->Instance->CR2, ADC_CR2_RSTCAL))
    {
    
    
      if((HAL_GetTick() - tickstart) > ADC_CALIBRATION_TIMEOUT)
      {
    
    
        /*新检查,避免抢占时错误超时检测*/
        if(HAL_IS_BIT_SET(hadc->Instance->CR2, ADC_CR2_RSTCAL))
        {
    
    
         /*更新ADC状态机为错误*/
          ADC_STATE_CLR_SET(hadc->State,
                            HAL_ADC_STATE_BUSY_INTERNAL,
                            HAL_ADC_STATE_ERROR_INTERNAL);

          __HAL_UNLOCK(hadc);

          return HAL_ERROR;
        }
      }
    }
    
    /* 4. 开始ADC校准*/
    SET_BIT(hadc->Instance->CR2, ADC_CR2_CAL);
    
    tickstart = HAL_GetTick();  

   /*等待校准完成*/
    while(HAL_IS_BIT_SET(hadc->Instance->CR2, ADC_CR2_CAL))
    {
    
    
      if((HAL_GetTick() - tickstart) > ADC_CALIBRATION_TIMEOUT)
      {
    
    
        /*新检查,避免抢占时错误超时检测*/
        if(HAL_IS_BIT_SET(hadc->Instance->CR2, ADC_CR2_CAL))
        {
    
    
         /*更新ADC状态机为错误*/
          ADC_STATE_CLR_SET(hadc->State,
                            HAL_ADC_STATE_BUSY_INTERNAL,
                            HAL_ADC_STATE_ERROR_INTERNAL);

          __HAL_UNLOCK(hadc);

          return HAL_ERROR;
        }
      }
    }
    
    /* 设置ADC状态 */
    ADC_STATE_CLR_SET(hadc->State,
                      HAL_ADC_STATE_BUSY_INTERNAL,
                      HAL_ADC_STATE_READY);
  }
  
  __HAL_UNLOCK(hadc);
  
  return tmp_hal_status;
}


五、知识点补充

(1)Beta值如何确定?
B,称作B值, NTC热敏电阻特定的材料常数(Beta)。

热敏电阻名称:SDNT2012X103F3950FTF
在这里插入图片描述
(2)ADC基准电压与采样电压有何区别?
每个STM32芯片都有一个内部的参照电压,相当于一个标准电压测量点,在芯片内部连接到ADC1的通道17。
根据数据手册中的数据,这个参照电压的典型值是1.20V,最小值是1.16V,最大值是1.24V。这个电压基本不随外部供电电压的变化而变化。
在这里插入图片描述
这个参照电压与ADC的参考电压不同。ADC的参考电压都是通过Vref+提供的。
100脚以上的型号,Vref+引到了片外,引脚名称为Vref+;
64脚和小于64脚的型号,Vref+在芯片内部与VCC信号线相连,没有引到片外,这样AD的参考电压就是VCC上的电压。

(3)公式详解
输出电压值Vadc和ADC采集数据Dadc之间的关系

Vadc = (Dadc*Vref)/(2^12)
Vadc : 输出电压值Vadc
Dadc :ADC采集数据
Vref :基准电压
12 : ADC为12位

热敏电阻值R和输出电压值Vadc之间关系

R = (Vadc*Rm)/(Vcc-Vadc)
R : 热敏电阻
Vadc :输出电压值Vadc
Rm :测量电阻
Vcc:采样电压

温度T和热敏电阻值R之间关系

Rt = RnEXP(B(1/T-1/Tn))
Rt :NTC在温度T(K)下的电阻值(单位Ω)
Rn:NTC在温度Tn(K)下的电阻值(单位Ω)
B :NTC热敏电阻特定的材料常数(Beta)

注:公式中温度都是以K为单位计算;K与摄氏度之间关系:T(K)=273.15+T(℃)

(4)误差存在哪些方面?
   [1] 硬件方面:VDDA_MCU和R11的精确度
在这里插入图片描述
   [2] ADC的基准电压
   [3] ADC分辨率 (ADC位数)
   [4] ADC软件校准 非常重要!!!!!!

(5)分辨率和精度的区别

分辨率(Resolution)是指ADC能够分辨量化的最小信号的能力,用二进制位数表示。
比如:一个10位的ADC,其所能分辨的最小量化电平为参考电平(满量程)的2的10次方分之一。
分辨率越高,就可以将满量程里的电平分出更多份数,得到的结果就越精确,得到的数字信号再用DAC转换回去后就越接近原来输入的模拟值。
所以,对于给定的一个具体ADC器件,其分辨率值是固定的。

精度(Precision)是指对于给定模拟输入,实际数字输出与理论预期数字输出之间的接近度(误差值是多少)。
换而言之,转换器的精度决定了数字输出代码中有多少个比特表示有关输入信号的有用信息。
对于给定的一个具体ADC器件,其精度值可能会受外界环境(温度、干扰等)的影响而变化。


六、结果演示

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43564241/article/details/130003270