一、核心原理与硬件基础
1. 内部温度传感器简介
STM32多数型号(如F1/F4/L0系列)内置温度传感器,用于监测芯片内部温度,其核心特性:
- 连接通道 :STM32F103系列中,内部温度传感器连接ADC1的通道16 (需使能
TSVREFE位)。 - 测量范围:-40℃~125℃(具体以数据手册为准)。
- 精度:±1.5℃(典型值,受VDDA电压、采样时间影响)。
- 转换公式:基于传感器输出电压与温度的线性关系(需参考芯片数据手册)。
2. 温度计算原理
根据STM32F103数据手册,内部温度传感器输出电压VSENSEV_{SENSE}VSENSE与温度TTT的关系为:
VSENSE=V25−(T−25)×Avg_SlopeV_{SENSE} = V_{25} - (T - 25) \times \text{Avg\_Slope}VSENSE=V25−(T−25)×Avg_Slope
其中:
- V25V_{25}V25:25℃时的输出电压(典型值1.43V);
- Avg_Slope\text{Avg\_Slope}Avg_Slope:温度系数(典型值4.3mV/℃);
- TTT:实际温度(℃)。
通过ADC采集VSENSEV_{SENSE}VSENSE对应的数字量,反推温度:
T=25+V25−VSENSEAvg_SlopeT = 25 + \frac{V_{25} - V_{SENSE}}{\text{Avg\_Slope}}T=25+Avg_SlopeV25−VSENSE
其中,VSENSE=ADC值×VDDA4095V_{SENSE} = \frac{\text{ADC值} \times V_{\text{DDA}}}{4095}VSENSE=4095ADC值×VDDA(12位ADC,VDDAV_{\text{DDA}}VDDA为ADC参考电压,通常3.3V)。
二、程序设计(基于STM32F103标准库)
1. 核心函数组成
| 函数 | 功能 | 依赖库文件 |
|---|---|---|
ADC1_TempSensor_Init |
初始化ADC1及内部温度传感器通道 | stm32f10x_adc.c、stm32f10x_rcc.c |
ADC1_Read_Temp |
读取ADC值并计算温度(℃) | stm32f10x_adc.c |
2. 完整代码实现
2.1 头文件与宏定义(temp_sensor.h)
c
#ifndef __TEMP_SENSOR_H
#define __TEMP_SENSOR_H
#include "stm32f10x.h"
// ADC参数定义(STM32F103)
#define ADC1_DR_Address ((uint32_t)0x4001244C) // ADC1数据寄存器地址
#define TEMP_SENSOR_CH ADC_Channel_16 // 内部温度传感器通道(ADC1_CH16)
#define VDDA_VOLTAGE 3.3f // ADC参考电压(单位:V)
#define V25 1.43f // 25℃时传感器输出电压(单位:V)
#define AVG_SLOPE 0.0043f // 温度系数(4.3mV/℃,单位:V/℃)
// 函数声明
void ADC1_TempSensor_Init(void); // 初始化ADC1及温度传感器
float ADC1_Read_Temp(void); // 读取温度值(返回℃)
#endif /* __TEMP_SENSOR_H */
2.2 源文件实现(temp_sensor.c)
c
#include "temp_sensor.h"
#include "stm32f10x_adc.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
/**
* @brief 初始化ADC1及内部温度传感器通道
* @param 无
* @retval 无
*/
void ADC1_TempSensor_Init(void) {
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
// 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(STM32F103最高ADC时钟)
// 3. 配置GPIO(内部温度传感器无需外部引脚,此处仅为占位)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 示例引脚(实际不使用)
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 4. ADC初始化(独立模式、单次转换、软件触发)
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 单通道模式(非扫描)
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; // 单次转换(非连续)
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 软件触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; // 转换通道数:1(通道16)
ADC_Init(ADC1, &ADC_InitStructure);
// 5. 配置温度传感器通道(通道16,采样时间239.5周期)
ADC_RegularChannelConfig(ADC1, TEMP_SENSOR_CH, 1, ADC_SampleTime_239Cycles5);
// 6. 使能内部温度传感器和Vrefint通道(关键!)
ADC_TempSensorVrefintCmd(ENABLE); // 需在ADC使能前调用
// 7. 使能ADC1并校准
ADC_Cmd(ADC1, ENABLE);
ADC_ResetCalibration(ADC1); // 复位校准寄存器
while (ADC_GetResetCalibrationStatus(ADC1)); // 等待复位完成
ADC_StartCalibration(ADC1); // 开始校准
while (ADC_GetCalibrationStatus(ADC1)); // 等待校准完成
}
/**
* @brief 读取ADC值并计算温度(℃)
* @param 无
* @retval 温度值(浮点数,单位℃)
*/
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;
}
3. 主程序调用示例(main.c)
c
#include "stm32f10x.h"
#include "temp_sensor.h"
#include "stdio.h"
// 重定向printf到串口(可选,用于调试输出)
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE {
USART_SendData(USART1, (uint8_t)ch);
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return ch;
}
int main(void) {
float temperature;
// 初始化系统时钟(72MHz,省略具体代码)
SystemInit();
// 初始化串口(用于调试输出,可选)
USART1_Init(115200); // 假设已实现串口初始化函数
// 初始化ADC1及温度传感器
ADC1_TempSensor_Init();
while (1) {
// 读取温度(每秒1次)
temperature = ADC1_Read_Temp();
printf("Chip Temperature: %.2f ℃\r\n", temperature); // 串口输出
// 延时1秒(可通过SysTick实现)
Delay_ms(1000);
}
}
// 简单延时函数(毫秒级)
void Delay_ms(uint32_t ms) {
uint32_t i;
for (; ms > 0; ms--)
for (i = 0; i < 7200; i++); // 72MHz时钟下约1ms
}
参考代码 STM32 测量内部温度传感器程序(库函数) www.youwenfan.com/contentcst/133729.html
三、关键注意事项
1. 硬件前提
- VDDA电压 :确保ADC参考电压VDDAV_{\text{DDA}}VDDA稳定(通常3.3V),若实际电压偏离,需修改代码中
VDDA_VOLTAGE宏定义。 - 芯片型号差异 :不同STM32型号的传感器参数(V25V_{25}V25、Avg_Slope\text{Avg\Slope}Avg_Slope)可能不同(如F4系列V25=0.76VV{25}=0.76VV25=0.76V,Avg_Slope=2.5mV/℃\text{Avg\_Slope}=2.5mV/℃Avg_Slope=2.5mV/℃),需查阅对应数据手册。
2. 软件优化
- 多次采样平均 :单次采样误差较大,建议连续采样5~10次取平均值(如
adc_value = (adc_value1 + adc_value2 + ...) / n)。 - 校准必要性 :ADC校准(
ADC_StartCalibration)可减少转换误差,必须在ADC使能前完成。 - 采样时间:内部温度传感器响应较慢,建议使用最长采样时间(239.5周期),确保转换精度。
3. 常见问题排查
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 温度值恒为0或异常 | 未使能TSVREFE位(ADC_TempSensorVrefintCmd) |
调用ADC_TempSensorVrefintCmd(ENABLE) |
| 温度波动大 | 电源噪声或单次采样误差 | 增加采样次数取平均,靠近芯片放置去耦电容 |
| ADC转换超时 | ADC时钟过快(超过14MHz) | 降低RCC_ADCCLKConfig分频系数(如RCC_PCLK2_Div8) |
四、扩展应用
1. 温度报警功能
c
// 温度超限报警(阈值30℃)
#define TEMP_THRESHOLD 30.0f
if (temperature > TEMP_THRESHOLD) {
GPIO_SetBits(GPIOB, GPIO_Pin_0); // 触发GPIO输出(如LED报警)
}
2. 低功耗优化
- 休眠模式 :读取温度后关闭ADC(
ADC_Cmd(ADC1, DISABLE)),需要时再开启。 - DMA传输:通过DMA自动读取ADC值,减少CPU干预(适用于多通道采样)。
五、总结
本程序基于STM32标准库实现了内部温度传感器的读取与温度计算,核心步骤包括ADC初始化 、传感器通道配置 、ADC值读取 及公式换算。使用时需注意芯片型号差异与硬件参数校准,适用于芯片温度监控、过热保护等场景。
核心价值:无需外部传感器,低成本实现STM32内部温度监测,为嵌入式系统的热管理提供基础支持。