STM32 内部温度测量程序(标准库/HAL库双版本)
一、核心原理与硬件基础
1. 内部温度传感器简介
STM32多数型号(如F1/F4/L0系列)内置温度传感器,用于监测芯片内部温度,核心特性:
- 连接通道:
- STM32F103:ADC1通道16(需使能
TSVREFE位); - STM32F407:ADC1通道18(需使能
TEMPSENSOR位); - 其他型号:参考对应数据手册(如F429为ADC1通道18)。
- STM32F103:ADC1通道16(需使能
- 测量范围:-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库实现思路一致,仅函数名和配置方式略有差异,适用于芯片温度监控、过热保护等场景。

浙公网安备 33010602011771号