STM32实现LM19温度精准测量 参考资料ADC采样:【stm32-hal】ADC模拟-数字转换技术电压转温度公式LM19温度传感器数据手册一、LM19核心要点供电2.7~ 5.5V可测-55~ 130℃2.4~ 2.7V仅-30~130℃STM32常用3.3V供电输出模拟电压信号温度越高输出电压越小抛物线公式V O − 3.88 × 10 − 6 T 2 − 0.0115 T 1.8639 V_O-3.88×10^{-6}T^2-0.0115T1.8639VO​−3.88×10−6T2−0.0115T1.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.962.1962×1063.88×10−61.8639−VO​​​引脚(TO92)1VCC、2VOUT、3GND二、硬件接线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.配置开启ADC时钟配置IO为模拟输入ADC配置单次/连续转换、12位分辨率、内部参考电压3.3VADC采样值换算电压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_valHAL_ADC_GetValue(hadc1);//2.换算输出电压(V)floatVoadc_val*3.3f/4095.0f;//3.带入LM19反算公式求温度floattemp-1481.96fsqrt(2196200.0f(1.8639f-Vo)/3.88e-6f);3.简化方案小量程近似线性-30~100℃适用V O − 0.01177 × T 1.8605 V_O -0.01177×T1.8605VO​−0.01177×T1.8605T ( 1.8605 − V O ) / 0.01177 T(1.8605-V_O)/0.01177T(1.8605−VO​)/0.01177计算简单、单片机运算快日常测温优先用此式。四、误差优化采样滤波连续采10~20次ADC取平均降低噪声自发热忽略LM19静态电流≤10μA自升温0.02℃无需补偿电源稳压STM32 3.3V不稳会带来ADC误差必要时校准ADC参考电压五、示例常用温度对照(快速校验)温度Vo电压0℃1.8639V25℃1.574V30℃1.515V100℃0.675V六、代码根据【stm32-hal】ADC模拟-数字转换技术中配置ADCmain()/* Includes ------------------------------------------------------------------*/#includemain.h#includeadc.h#includegpio.h#includemath.h/* Private includes ----------------------------------------------------------*//** * brief The application entry point. * retval int */intvalue0;floatvoltage0.0;floattemp0.0;//ADC多次采样平均值times采样次数uint16_tGet_Adc_Average(uint8_ttimes){uint32_tadc_sum0;for(uint8_ti0;itimes;i){// HAL_ADC_PollForConversion(hadc1,HAL_MAX_DELAY);//已开启连续转换模式只用写一次可注释adc_sumHAL_ADC_GetValue(hadc1);}returnadc_sum/times;}//LM19电压转温度floatLM19_GetTemp(floatVo){return-1481.96fsqrtf(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 */valueGet_Adc_Average(20);//20次平均voltagevalue*3.3f/4095.0f;tempLM19_GetTemp(voltage);/* USER CODE BEGIN 3 */}/* USER CODE END 3 */}adc.c/* Includes ------------------------------------------------------------------*/#includeadc.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.InstanceADC1;hadc1.Init.ScanConvModeADC_SCAN_DISABLE;hadc1.Init.ContinuousConvModeENABLE;hadc1.Init.DiscontinuousConvModeDISABLE;hadc1.Init.ExternalTrigConvADC_SOFTWARE_START;hadc1.Init.DataAlignADC_DATAALIGN_RIGHT;hadc1.Init.NbrOfConversion1;if(HAL_ADC_Init(hadc1)!HAL_OK){Error_Handler();}/** Configure Regular Channel */sConfig.ChannelADC_CHANNEL_15;sConfig.RankADC_REGULAR_RANK_1;sConfig.SamplingTimeADC_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-InstanceADC1){/* 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.PinGPIO_PIN_5;GPIO_InitStruct.ModeGPIO_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-InstanceADC1){/* 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 */时钟配置将原来的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.OscillatorTypeRCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEStateRCC_HSE_ON;RCC_OscInitStruct.HSEPredivValueRCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIStateRCC_HSI_ON;RCC_OscInitStruct.PLL.PLLStateRCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSourceRCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMULRCC_PLL_MUL9;if(HAL_RCC_OscConfig(RCC_OscInitStruct)!HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks */RCC_ClkInitStruct.ClockTypeRCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSourceRCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDividerRCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDividerRCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDividerRCC_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.OscillatorTypeRCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEStateRCC_HSE_ON;RCC_OscInitStruct.HSEPredivValueRCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIStateRCC_HSI_ON;RCC_OscInitStruct.PLL.PLLStateRCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSourceRCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMULRCC_PLL_MUL9;if(HAL_RCC_OscConfig(RCC_OscInitStruct)!HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks */RCC_ClkInitStruct.ClockTypeRCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSourceRCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDividerRCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDividerRCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDividerRCC_HCLK_DIV1;if(HAL_RCC_ClockConfig(RCC_ClkInitStruct,FLASH_LATENCY_2)!HAL_OK){Error_Handler();}PeriphClkInit.PeriphClockSelectionRCC_PERIPHCLK_ADC;PeriphClkInit.AdcClockSelectionRCC_ADCPCLK2_DIV6;//ADCPrescaler DIV6 → ADC_CLK72/612MHzif(HAL_RCCEx_PeriphCLKConfig(PeriphClkInit)!HAL_OK){Error_Handler();}}否则测到的电压偏大温度偏低核心原因ADC时钟变了 → ADC采样精度变 → 电压算错 → 温度飘STM32F1ADC最大时钟不能超过14MHz这是关键限制1、原来配置ADCPrescalerDIV2 SYSCLKHSE*972M → APB272M → ADC_CLK72/236MHz超标(14M)ADC工作异常、采样跳变不准温度乱飘。2、修改后ADCPrescalerDIV6 → ADC_CLK72/612MHz12MHz14MHzADC进入标准正常工作区间采样真实电压温度自然变准。快速总结DIV236M超规格 → ADC采样失真温度错误DIV612M合规 → ADC读数真实温度正确配套优化进一步稳温度ADC采样时间从1.5cycle改成长采样sConfig.SamplingTimeADC_SAMPLETIME_239CYCLES_5;七、现象打开调试器可以观察到temp等数据在不断变化。