STM32 内部温度测量程序(标准库/HAL库双版本)

一、核心原理与硬件基础

1. 内部温度传感器简介

STM32多数型号(如F1/F4/L0系列)内置温度传感器,用于监测芯片内部温度,核心特性:

  • 连接通道
    • STM32F103:ADC1通道16(需使能TSVREFE位);
    • STM32F407:ADC1通道18(需使能TEMPSENSOR位);
    • 其他型号:参考对应数据手册(如F429为ADC1通道18)。
  • 测量范围:-40℃~125℃(典型值)。
  • 精度:±1.5℃(受VDDA电压、采样时间影响)。
  • 转换公式:基于传感器输出电压与温度的线性关系(需参考芯片数据手册)。

2. 温度计算原理(以STM32F103为例)

根据数据手册,传感器输出电压\(V_{SENSE}\)与温度\(T\)的关系:

\[V_{SENSE} = V_{25} - (T - 25) \times \text{Avg\_Slope} \]

  • \(V_{25}\):25℃时输出电压(典型值1.43V);
  • \(\text{Avg\_Slope}\):温度系数(典型值4.3mV/℃);
  • 反推温度:

    \[T = 25 + \frac{V_{25} - V_{SENSE}}{\text{Avg\_Slope}} \]

  • 其中,\(V_{SENSE} = \frac{\text{ADC值} \times V_{\text{DDA}}}{4095}\)(12位ADC,\(V_{\text{DDA}}\)为ADC参考电压,通常3.3V)。

二、硬件连接(以STM32F103C8T6为例)

  • 无需外部电路:内部温度传感器集成于芯片内,仅需通过ADC通道采集。
  • 关键引脚
    • ADC1通道16(PA0,部分型号可能为其他引脚,需查数据手册);
    • VDDA(3.3V,需稳定供电,建议并联0.1μF去耦电容)。

三、软件实现(标准库版)

1. 核心代码(基于STM32F103标准库)

1.1 头文件与宏定义(temp_sensor.h

#ifndef __TEMP_SENSOR_H
#define __TEMP_SENSOR_H

#include "stm32f10x.h"

// ADC参数(STM32F103,LSI=40kHz,VDDA=3.3V)
#define ADC1_TEMP_CH     ADC_Channel_16  // 内部温度传感器通道
#define VDDA_VOLTAGE     3.3f            // ADC参考电压(V)
#define V25             1.43f           // 25℃时传感器输出电压(V)
#define AVG_SLOPE        0.0043f         // 温度系数(4.3mV/℃,V/℃)
#define ADC_SAMPLE_TIME  ADC_SampleTime_239Cycles5  // 最长采样时间(确保精度)

// 函数声明
void ADC1_TempSensor_Init(void);  // 初始化ADC1及温度传感器
float ADC1_Read_Temp(void);       // 读取温度值(℃)

#endif /* __TEMP_SENSOR_H */

1.2 源文件实现(temp_sensor.c

#include "temp_sensor.h"
#include "stm32f10x_adc.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"

void ADC1_TempSensor_Init(void) {
    ADC_InitTypeDef ADC_InitStruct;
    GPIO_InitTypeDef GPIO_InitStruct;

    // 1. 使能时钟(ADC1、GPIOA、AFIO)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
    
    // 2. 配置ADC时钟(PCLK2分频,最大14MHz)
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);  // 72MHz/6=12MHz(F103最高ADC时钟)
    
    // 3. 配置GPIO(模拟输入)
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;  // 通道16对应PA0(F103)
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
    
    // 4. ADC初始化(独立模式、单次转换、软件触发)
    ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStruct.ADC_ScanConvMode = DISABLE;       // 单通道
    ADC_InitStruct.ADC_ContinuousConvMode = DISABLE; // 单次转换
    ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  // 软件触发
    ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;  // 右对齐
    ADC_InitStruct.ADC_NbrOfChannel = 1;
    ADC_Init(ADC1, &ADC_InitStruct);
    
    // 5. 配置温度传感器通道(通道16,采样时间239.5周期)
    ADC_RegularChannelConfig(ADC1, ADC1_TEMP_CH, 1, ADC_SAMPLE_TIME);
    
    // 6. 使能内部温度传感器和Vrefint(关键!)
    ADC_TempSensorVrefintCmd(ENABLE);  // 必须在ADC使能前调用
    
    // 7. 使能ADC并校准
    ADC_Cmd(ADC1, ENABLE);
    ADC_ResetCalibration(ADC1);  // 复位校准
    while (ADC_GetResetCalibrationStatus(ADC1));  // 等待复位完成
    ADC_StartCalibration(ADC1);  // 开始校准
    while (ADC_GetCalibrationStatus(ADC1));  // 等待校准完成
}

float ADC1_Read_Temp(void) {
    uint16_t adc_value;
    float voltage, temp;

    // 1. 启动ADC转换(软件触发)
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    
    // 2. 等待转换完成(EOC标志)
    while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
    
    // 3. 读取ADC原始值(12位,0~4095)
    adc_value = ADC_GetConversionValue(ADC1);
    
    // 4. 计算传感器电压(V)
    voltage = (float)adc_value * VDDA_VOLTAGE / 4095.0f;
    
    // 5. 代入公式计算温度(℃)
    temp = 25.0f + (V25 - voltage) / AVG_SLOPE;
    
    return temp;  // 返回温度值
}

1.3 主程序调用示例(main.c

#include "stm32f10x.h"
#include "temp_sensor.h"
#include "usart.h"  // 假设已实现串口初始化(用于打印)

int main(void) {
    float temp;
    SystemInit();       // 系统时钟初始化(72MHz)
    USART1_Init(115200);  // 串口初始化(调试用)
    ADC1_TempSensor_Init();  // 初始化ADC及温度传感器

    while (1) {
        temp = ADC1_Read_Temp();  // 读取温度
        printf("Internal Temp: %.2f ℃\r\n", temp);  // 串口输出
        Delay_ms(1000);  // 延时1秒(需实现Delay_ms函数)
    }
}

四、软件实现(HAL库版,以STM32F407为例)

1. 核心代码(HAL库)

1.1 初始化函数(temp_sensor_hal.c

#include "temp_sensor_hal.h"
#include "stm32f4xx_hal.h"

ADC_HandleTypeDef hadc1;

void ADC1_TempSensor_Init(void) {
    ADC_ChannelConfTypeDef sConfig = {0};

    // 1. 使能时钟
    __HAL_RCC_ADC1_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();

    // 2. ADC配置
    hadc1.Instance = ADC1;
    hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;  // 84MHz/4=21MHz(F407 ADC最大36MHz)
    hadc1.Init.Resolution = ADC_RESOLUTION_12B;
    hadc1.Init.ScanConvMode = DISABLE;
    hadc1.Init.ContinuousConvMode = DISABLE;
    hadc1.Init.DiscontinuousConvMode = DISABLE;
    hadc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
    hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
    hadc1.Init.NbrOfConversion = 1;
    hadc1.Init.DMAContinuousRequests = DISABLE;
    hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
    HAL_ADC_Init(&hadc1);

    // 3. 配置温度传感器通道(F407为通道18)
    sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;  // 内部温度传感器通道
    sConfig.Rank = 1;
    sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;  // 480周期采样(F407需更长采样时间)
    HAL_ADC_ConfigChannel(&hadc1, &sConfig);

    // 4. 使能温度传感器(HAL库自动处理TSVREFE位)
    HAL_ADCEx_EnableInternalRegulator(&hadc1);
    HAL_Delay(10);  // 等待内部稳压器稳定
}

float ADC1_Read_Temp_HAL(void) {
    uint32_t adc_value;
    float voltage, temp;

    HAL_ADC_Start(&hadc1);  // 启动转换
    HAL_ADC_PollForConversion(&hadc1, 10);  // 等待转换完成
    adc_value = HAL_ADC_GetValue(&hadc1);  // 读取ADC值

    // F407参数:V25=0.76V,Avg_Slope=0.0025V/℃(数据手册)
    voltage = (float)adc_value * 3.3f / 4095.0f;  // VDDA=3.3V
    temp = 25.0f + (0.76f - voltage) / 0.0025f;  // 代入F407公式

    return temp;
}

参考代码 STM32 测量内部温度程序 www.youwenfan.com/contentcnt/133742.html

五、关键注意事项

1. 硬件前提

  • VDDA稳定:确保ADC参考电压\(V_{\text{DDA}}\)稳定(3.3V),若偏差大需修改代码中VDDA_VOLTAGE
  • 芯片型号差异:不同型号参数不同(如F4系列\(V_{25}=0.76V\)\(\text{Avg\_Slope}=2.5mV/℃\)),需查数据手册。

2. 软件优化

  • 多次采样平均:单次采样误差大,建议连续采样5~10次取平均(如adc_value = (val1+val2+...+val5)/5)。
  • 采样时间:内部传感器响应慢,用最长采样时间(F1:239.5周期,F4:480周期)。

3. 常见问题排查

问题 原因 解决方案
温度值恒为0或异常 未使能TSVREFE位(标准库ADC_TempSensorVrefintCmd(ENABLE) 检查使能代码是否执行
温度波动大 电源噪声或单次采样误差 增加采样次数取平均,加去耦电容
ADC转换超时 ADC时钟过快(超过14MHz) 降低RCC_ADCCLKConfig分频系数

六、扩展应用

  • 温度报警:设置阈值(如>60℃),触发GPIO输出(LED/蜂鸣器)。
  • 低功耗优化:读取后关闭ADC(ADC_Cmd(ADC1, DISABLE)),需时再开启。
  • 数据记录:将温度存入EEPROM,通过串口上传至上位机。

七、总结

STM32内部温度测量通过ADC采集传感器电压+公式换算实现,核心是确保ADC配置正确(通道、采样时间、使能传感器)和参数准确(依芯片型号调整)。标准库与HAL库实现思路一致,仅函数名和配置方式略有差异,适用于芯片温度监控、过热保护等场景。

posted @ 2026-04-14 17:47  yes_go  阅读(238)  评论(0)    收藏  举报