在嵌入式系统开发中,温度监测是确保设备稳定运行的关键环节。STM32系列微控制器内置了温度传感器,通过ADC(模数转换器)可以方便地获取芯片内部温度。这种方式相比外接温度传感器具有成本低、占用PCB空间小、无需额外布线的优势。
STM32内部温度传感器本质上是一个输出电压随温度变化的PN结,其输出特性曲线与温度呈线性关系。传感器输出连接到ADC1_IN16或ADC1_IN18输入通道(具体通道号取决于STM32型号),通过12位ADC将模拟电压转换为数字值。根据STM32参考手册,温度传感器在出厂时已经过校准,典型精度为±1.5°C(-40°C到+125°C范围)。
重要提示:内部温度传感器测量的是芯片结温,而非环境温度。当芯片处于高负载状态时,两者可能有显著差异。对于精确环境温度测量,仍需使用外部传感器。
在STM32CubeMX中配置温度传感器采集需要以下步骤:
关键配置参数示例(以HAL库为例):
c复制ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = ADC_CHANNEL_TEMPSENSOR;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
温度传感器输出阻抗较高(约10kΩ),需要足够长的采样时间确保ADC采样电容充分充电。根据STM32F4系列数据手册:
实际工程中,建议通过实验确定最优采样时间。可通过以下方法验证:
STM32温度传感器输出电压与温度的关系由以下公式决定:
code复制T(°C) = {(V25 - Vsense)/Avg_Slope} + 25
其中:
实际代码实现示例:
c复制float Get_Temperature(void)
{
uint32_t adc_value = 0;
float temperature = 0;
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 10);
adc_value = HAL_ADC_GetValue(&hadc1);
// 假设使用3.3V参考电压,12位ADC
float vsense = (float)adc_value * 3.3f / 4095.0f;
// F4系列校准参数
temperature = ((1.43f - vsense) / 0.0043f) + 25.0f;
return temperature;
}
出厂校准参数存在个体差异,可通过两点校准进一步提高精度:
code复制Slope_actual = (T2 - T1) / (AD2 - AD1)
Offset = T1 - AD1 * Slope_actual
code复制T_calibrated = ADC_value * Slope_actual + Offset
校准代码实现:
c复制// 校准参数存储结构体
typedef struct {
float slope;
float offset;
} TempCalib_t;
TempCalib_t temp_calib;
void Temp_Calibrate(float T1, uint32_t AD1, float T2, uint32_t AD2)
{
temp_calib.slope = (T2 - T1) / (float)(AD2 - AD1);
temp_calib.offset = T1 - (float)AD1 * temp_calib.slope;
}
float Get_CalibratedTemp(uint32_t adc_value)
{
return (float)adc_value * temp_calib.slope + temp_calib.offset;
}
实测中发现温度读数可能存在±2°C的波动,可通过以下方法改善:
硬件措施:
软件滤波:
c复制#define FILTER_WINDOW 16
uint32_t adc_buffer[FILTER_WINDOW];
uint8_t buf_index = 0;
float Get_FilteredTemp(void)
{
uint32_t sum = 0;
adc_buffer[buf_index] = HAL_ADC_GetValue(&hadc1);
buf_index = (buf_index + 1) % FILTER_WINDOW;
for(int i=0; i<FILTER_WINDOW; i++){
sum += adc_buffer[i];
}
float vsense = (float)(sum/FILTER_WINDOW) * 3.3f / 4095.0f;
return ((1.43f - vsense) / 0.0043f) + 25.0f;
}
对于电池供电设备,可采用间歇采样策略:
关键代码片段:
c复制void Enter_LowPowerMode(void)
{
// 配置唤醒源为RTC
HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 10, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
// 进入STOP模式
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
// 唤醒后重新初始化时钟
SystemClock_Config();
}
void RTC_WKUP_IRQHandler(void)
{
HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
HAL_RTCEx_WakeUpTimerIRQHandler(&hrtc);
// 执行温度采样
float temp = Get_Temperature();
Process_Temperature(temp);
// 返回低功耗模式
Enter_LowPowerMode();
}
某些应用场景需要根据温度调整系统时钟:
c复制void Adjust_ClockBasedOnTemp(float temperature)
{
if(temperature > 70.0f) {
// 高温降频
SystemClock_Decrease();
}
else if(temperature < -20.0f) {
// 低温时特殊处理
Handle_LowTempCondition();
}
else {
// 正常温度范围
SystemClock_Normal();
}
}
结合PWM实现智能温控风扇:
c复制#define TEMP_THRESHOLD_LOW 40.0f
#define TEMP_THRESHOLD_HIGH 70.0f
void Update_FanSpeed(float temperature)
{
static uint8_t pwm_duty = 0;
if(temperature < TEMP_THRESHOLD_LOW) {
pwm_duty = 0; // 关闭风扇
}
else if(temperature > TEMP_THRESHOLD_HIGH) {
pwm_duty = 100; // 全速运转
}
else {
// 线性调节
pwm_duty = (uint8_t)((temperature - TEMP_THRESHOLD_LOW) /
(TEMP_THRESHOLD_HIGH - TEMP_THRESHOLD_LOW) * 100.0f);
}
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, pwm_duty);
}
在不同环境温度下采集的典型数据对比:
| 环境温度 (°C) | 原始ADC值 | 计算温度 (°C) | 校准后温度 (°C) |
|---|---|---|---|
| 15.0 | 1520 | 16.2 | 15.1 |
| 25.0 | 1365 | 25.8 | 25.0 |
| 35.0 | 1210 | 35.4 | 35.2 |
| 45.0 | 1055 | 45.0 | 45.1 |
| 55.0 | 900 | 54.6 | 54.9 |
测试条件:
从实测数据可见,经过校准后温度误差可控制在±0.5°C以内,满足大多数应用需求。在高温区域(>70°C)误差会略有增大,这与芯片内部热梯度有关。