STM32实现LM19温度精准测量
2026/6/6 3:24:04 网站建设 项目流程

参考资料

ADC采样:
【stm32-hal】ADC模拟-数字转换技术
电压转温度公式:
LM19温度传感器数据手册

一、LM19核心要点

  1. 供电:2.7~ 5.5V可测-55~ +130℃;2.4~ 2.7V仅-30~+130℃,STM32常用3.3V供电
  2. 输出:模拟电压信号,温度越高输出电压越小
    抛物线公式:V O = − 3.88 × 10 − 6 T 2 − 0.0115 T + 1.8639 V_O=-3.88×10^{-6}T^2-0.0115T+1.8639VO=3.88×106T20.0115T+1.8639
    测温反推:T = − 1481.96 + 2.1962 × 10 6 + 1.8639 − V O 3.88 × 10 − 6 T=-1481.96+\sqrt{2.1962×10^6+\frac{1.8639-V_O}{3.88×10^{-6}}}T=1481.96+2.1962×106+3.88×1061.8639VO
  3. 引脚(TO92):1=VCC、2=VOUT、3=GND

二、硬件接线

LM19引脚STM32备注
V+(1脚)3.3V严禁5V超压可选
GND(3脚)GND共地
VOUT(2脚)STM32 ADC输入引脚(PA0/PA1等)
外围推荐:电源端加0.1μF去耦电容;长线干扰大时:VOUT串200Ω+1μF到GND滤波

注意:LM19最大输出约2.485V(-55℃)<3.3V,可直接接入3.3V量程ADC

三、STM32软件思路(HAL库为例)

1.配置

  1. 开启ADC时钟,配置IO为模拟输入
  2. ADC配置:单次/连续转换、12位分辨率、内部参考电压3.3V
  3. ADC采样值换算电压:
    V o u t ( V ) = A D C v a l × 3.3 4095 V_{out}(V)=\frac{ADC_{val}×3.3}{4095}Vout(V)=4095ADCval×3.3

2.关键代码逻辑

//1.ADC读取原始值uint16_tadc_val=HAL_ADC_GetValue(&hadc1);//2.换算输出电压(V)floatVo=adc_val*3.3f/4095.0f;//3.带入LM19反算公式求温度floattemp=-1481.96f+sqrt(2196200.0f+(1.8639f-Vo)/3.88e-6f);

3.简化方案(小量程近似线性)

-30~100℃适用:V O = − 0.01177 × T + 1.8605 V_O = -0.01177×T+1.8605VO=0.01177×T+1.8605
T = ( 1.8605 − V O ) / 0.01177 T=(1.8605-V_O)/0.01177T=(1.8605VO)/0.01177
计算简单、单片机运算快,日常测温优先用此式。

四、误差优化

  1. 采样滤波:连续采10~20次ADC取平均,降低噪声
  2. 自发热忽略:LM19静态电流≤10μA,自升温<0.02℃,无需补偿
  3. 电源稳压:STM32 3.3V不稳会带来ADC误差,必要时校准ADC参考电压

五、示例:常用温度对照(快速校验)

温度Vo电压
0℃1.8639V
25℃1.574V
30℃1.515V
100℃0.675V

六、代码

根据【stm32-hal】ADC模拟-数字转换技术中配置ADC

  1. main()
/* Includes ------------------------------------------------------------------*/#include"main.h"#include"adc.h"#include"gpio.h"#include<math.h>/* Private includes ----------------------------------------------------------*//** * @brief The application entry point. * @retval int */intvalue=0;floatvoltage=0.0;floattemp=0.0;//ADC多次采样平均值,times:采样次数uint16_tGet_Adc_Average(uint8_ttimes){uint32_tadc_sum=0;for(uint8_ti=0;i<times;i++){// HAL_ADC_PollForConversion(&hadc1,HAL_MAX_DELAY);//已开启连续转换模式,只用写一次,可注释adc_sum+=HAL_ADC_GetValue(&hadc1);}returnadc_sum/times;}//LM19电压转温度floatLM19_GetTemp(floatVo){return-1481.96f+sqrtf(2196200.0f+(1.8639f-Vo)/3.88e-6f);}intmain(void){/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_ADC1_Init();/* USER CODE BEGIN 2 */HAL_ADCEx_Calibration_Start(&hadc1);HAL_ADC_Start(&hadc1);HAL_ADC_PollForConversion(&hadc1,HAL_MAX_DELAY);/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while(1){/* USER CODE END WHILE */value=Get_Adc_Average(20);//20次平均voltage=value*3.3f/4095.0f;temp=LM19_GetTemp(voltage);/* USER CODE BEGIN 3 */}/* USER CODE END 3 */}
  1. adc.c
/* Includes ------------------------------------------------------------------*/#include"adc.h"/* USER CODE BEGIN 0 *//* USER CODE END 0 */ADC_HandleTypeDef hadc1;/* ADC1 init function */voidMX_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.ScanConvMode=ADC_SCAN_DISABLE;hadc1.Init.ContinuousConvMode=ENABLE;hadc1.Init.DiscontinuousConvMode=DISABLE;hadc1.Init.ExternalTrigConv=ADC_SOFTWARE_START;hadc1.Init.DataAlign=ADC_DATAALIGN_RIGHT;hadc1.Init.NbrOfConversion=1;if(HAL_ADC_Init(&hadc1)!=HAL_OK){Error_Handler();}/** Configure Regular Channel */sConfig.Channel=ADC_CHANNEL_15;sConfig.Rank=ADC_REGULAR_RANK_1;sConfig.SamplingTime=ADC_SAMPLETIME_1CYCLE_5;if(HAL_ADC_ConfigChannel(&hadc1,&sConfig)!=HAL_OK){Error_Handler();}/* USER CODE BEGIN ADC1_Init 2 *//* USER CODE END ADC1_Init 2 */}voidHAL_ADC_MspInit(ADC_HandleTypeDef*adcHandle){GPIO_InitTypeDef GPIO_InitStruct={0};if(adcHandle->Instance==ADC1){/* USER CODE BEGIN ADC1_MspInit 0 *//* USER CODE END ADC1_MspInit 0 *//* ADC1 clock enable */__HAL_RCC_ADC1_CLK_ENABLE();__HAL_RCC_GPIOC_CLK_ENABLE();/**ADC1 GPIO Configuration PC5 ------> ADC1_IN15 */GPIO_InitStruct.Pin=GPIO_PIN_5;GPIO_InitStruct.Mode=GPIO_MODE_ANALOG;HAL_GPIO_Init(GPIOC,&GPIO_InitStruct);/* USER CODE BEGIN ADC1_MspInit 1 *//* USER CODE END ADC1_MspInit 1 */}}voidHAL_ADC_MspDeInit(ADC_HandleTypeDef*adcHandle){if(adcHandle->Instance==ADC1){/* USER CODE BEGIN ADC1_MspDeInit 0 *//* USER CODE END ADC1_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_ADC1_CLK_DISABLE();/**ADC1 GPIO Configuration PC5 ------> ADC1_IN15 */HAL_GPIO_DeInit(GPIOC,GPIO_PIN_5);/* USER CODE BEGIN ADC1_MspDeInit 1 *//* USER CODE END ADC1_MspDeInit 1 */}}/* USER CODE BEGIN 1 *//* USER CODE END 1 */
  1. 时钟配置

将原来的

voidSystemClock_Config(void){RCC_OscInitTypeDef RCC_OscInitStruct={0};RCC_ClkInitTypeDef RCC_ClkInitStruct={0};/** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */RCC_OscInitStruct.OscillatorType=RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState=RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue=RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState=RCC_HSI_ON;RCC_OscInitStruct.PLL.PLLState=RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource=RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL=RCC_PLL_MUL9;if(HAL_RCC_OscConfig(&RCC_OscInitStruct)!=HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks */RCC_ClkInitStruct.ClockType=RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider=RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider=RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider=RCC_HCLK_DIV1;if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct,FLASH_LATENCY_2)!=HAL_OK){Error_Handler();}}

改成

voidSystemClock_Config(void){RCC_OscInitTypeDef RCC_OscInitStruct={0};RCC_ClkInitTypeDef RCC_ClkInitStruct={0};RCC_PeriphCLKInitTypeDef PeriphClkInit={0};/** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */RCC_OscInitStruct.OscillatorType=RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState=RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue=RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState=RCC_HSI_ON;RCC_OscInitStruct.PLL.PLLState=RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource=RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL=RCC_PLL_MUL9;if(HAL_RCC_OscConfig(&RCC_OscInitStruct)!=HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks */RCC_ClkInitStruct.ClockType=RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider=RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider=RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider=RCC_HCLK_DIV1;if(HAL_RCC_ClockConfig(&RCC_ClkInitStruct,FLASH_LATENCY_2)!=HAL_OK){Error_Handler();}PeriphClkInit.PeriphClockSelection=RCC_PERIPHCLK_ADC;PeriphClkInit.AdcClockSelection=RCC_ADCPCLK2_DIV6;//ADCPrescaler = DIV6 → ADC_CLK=72/6=12MHzif(HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit)!=HAL_OK){Error_Handler();}}

否则,测到的电压偏大,温度偏低

核心原因:ADC时钟变了 → ADC采样精度变 → 电压算错 → 温度飘

STM32F1ADC最大时钟不能超过14MHz,这是关键限制:

1、原来配置
ADCPrescaler=DIV2 SYSCLK=HSE*9=72M → APB2=72M → ADC_CLK=72/2=36MHz

超标(>14M),ADC工作异常、采样跳变不准,温度乱飘。

2、修改后
ADCPrescaler=DIV6 → ADC_CLK=72/6=12MHz

12MHz<14MHz,ADC进入标准正常工作区间,采样真实电压,温度自然变准

快速总结
  1. DIV2:36M超规格 → ADC采样失真,温度错误
  2. DIV6:12M合规 → ADC读数真实,温度正确
配套优化(进一步稳温度)

ADC采样时间从1.5cycle改成长采样:

sConfig.SamplingTime=ADC_SAMPLETIME_239CYCLES_5;

七、现象

打开调试器可以观察到,temp等数据在不断变化。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询