别再只会用串口读温度了!手把手教你用STM32的ADC采集PT100模块信号并计算(附完整代码)
2026/6/7 4:55:52 网站建设 项目流程

深入解析PT100温度测量:从ADC采集到精准计算的STM32实战指南

在工业控制和精密测量领域,PT100铂电阻因其出色的稳定性和线性度成为温度测量的首选传感器之一。市面上常见的PT100模块大多采用"黑盒"设计,通过串口直接输出温度值,这种方式虽然简单易用,却限制了开发者在精度优化、系统集成和成本控制方面的灵活性。本文将带你深入PT100测量原理的核心,掌握如何绕过预封装模块的限制,直接使用STM32的ADC采集原始信号并实现高精度温度计算。

1. PT100测量原理与电路设计基础

PT100是一种正温度系数热电阻,其名称中的"100"表示在0℃时电阻值为100Ω。与常见的NTC热敏电阻相比,PT100在-200℃至+850℃范围内表现出更好的线性度和稳定性,特别适合工业级应用。

1.1 电桥测量原理

典型的三线制PT100测量电路采用惠斯通电桥设计,这种结构能有效消除引线电阻带来的误差:

Vcc | [R6] |---- V1 [PT100] |---- V2 [R7] | GND

当PT100电阻值等于R6时,电桥平衡(V1=V2);温度变化导致PT100阻值改变时,电桥输出与温度变化成正比的差分电压(V1-V2)。这个mV级信号需要经过精密运放放大后才能被ADC有效采集。

1.2 关键电路参数计算

以典型电路为例,假设:

  • 参考电压Vref = 3V
  • 平衡电阻R6 = R7 = 100Ω
  • 差分放大倍数G = R8/R12 = 20倍

当PT100在0℃时(100Ω),电桥输出电压:

V1 = 3V * (R6)/(R6 + PT100) = 1.5V V2 = 3V * (R7)/(R7 + R7) = 1.5V 差分输出 = 0V

当温度升至100℃时(PT100≈138.5Ω):

V1 = 3 * 100/(100 + 138.5) ≈ 1.257V V2 = 1.5V 差分输出 = 1.257V - 1.5V = -0.243V 放大后输出 = -0.243 * 20 ≈ -4.86V

注意:实际电路需要考虑运放的供电轨限制,单5V供电的运放通常无法输出低于0V或高于5V的信号,因此需要设计合适的偏置电压。

2. STM32硬件连接与ADC配置

2.1 模块与STM32的硬件接口

将PT100模块的模拟输出连接到STM32的ADC输入引脚时,需注意以下连接方式:

模块引脚STM32连接说明
VoutPA0主信号输入
GNDGND共地连接
Vref-可不连接

重要提示:确保模块和STM32共地,这是获得准确ADC读数的基础。长距离连接时,考虑使用屏蔽线减少噪声干扰。

2.2 STM32 ADC配置要点

使用STM32CubeMX配置ADC时,关键参数设置如下:

// ADC初始化结构体配置示例 hadc1.Instance = ADC1; hadc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; hadc1.Init.Resolution = ADC_RESOLUTION_12B; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.ScanConvMode = DISABLE; hadc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV; hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.NbrOfConversion = 1; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;

常见问题排查:

  1. 读数不稳定:尝试增加采样时间(hadc1.Init.SamplingTime)
  2. 值始终为0:检查引脚配置和硬件连接
  3. 读数饱和:确认输入电压在ADC量程范围内

2.3 多通道采样与滤波处理

为提高测量精度,建议采用以下策略:

#define SAMPLE_COUNT 32 uint32_t get_filtered_adc(ADC_HandleTypeDef* hadc) { uint32_t sum = 0; for(int i=0; i<SAMPLE_COUNT; i++){ HAL_ADC_Start(hadc); HAL_ADC_PollForConversion(hadc, HAL_MAX_DELAY); sum += HAL_ADC_GetValue(hadc); } return sum / SAMPLE_COUNT; }

这种移动平均滤波能有效抑制随机噪声,提高测量稳定性。在噪声较大的环境中,可考虑改用中值滤波或卡尔曼滤波算法。

3. 从ADC值到温度的计算方法

3.1 电压-电阻转换

根据电路原理,ADC读数首先需要转换为电压值:

float adc_to_voltage(uint32_t adc_value, float vref) { return (float)adc_value * vref / 4095.0f; // 12位ADC }

然后根据放大电路特性反推PT100电阻值:

float calculate_pt100_resistance(float voltage, float vref, float gain) { float v_diff = voltage / gain; float v1 = (v_diff + 2*vref/3) / 2; // 假设R6=R7=100Ω return (2000 * v1) / (vref - v1); }

3.2 电阻-温度转换方法

PT100电阻与温度的关系可通过以下三种方式计算:

  1. 查表法:使用标准分度表,通过查表插值获得温度

    typedef struct { int16_t temp; // 温度(℃) uint16_t resistance; // 电阻(Ω×10) } PT100_TableEntry; const PT100_TableEntry pt100_table[] = { {-200, 1840}, {-190, 1892}, // 简化的示例数据 // ...完整表格数据 {850, 3905} }; float lookup_temperature(float resistance) { // 实现二分查找和线性插值 }
  2. Callendar-Van Dusen公式

    对于t ≥ 0℃: R(t) = R0(1 + At + Bt²) 对于t < 0℃: R(t) = R0[1 + At + Bt² + C(t-100)t³] 其中: A = 3.9083×10⁻³ B = -5.775×10⁻⁷ C = -4.183×10⁻¹² (t<0℃时)
  3. 多项式近似(适合MCU快速计算):

    float resistance_to_temperature(float rt) { float temp; if(rt >= 100.0f) { // 正温度 temp = -242.02f + 2.2228f * rt; temp = 0.009109f * rt * temp + temp; temp = -0.0000001346f * rt * temp * temp + temp; } else { // 负温度 temp = -247.29f + 2.3992f * rt; temp = 0.00063962f * rt * temp + temp; temp = 0.00000063475f * rt * temp * temp + temp; } return temp; }

3.3 精度优化技巧

  1. 参考电压校准

    // 使用内部参考电压校准实际VREF float calibrate_vref(ADC_HandleTypeDef* hadc) { HAL_ADCEx_Calibration_Start(hadc, ADC_SINGLE_ENDED); uint32_t vrefint = read_vrefint(); // 读取内部参考电压ADC值 return 1.2f * 4095.0f / (float)vrefint; // 1.2V是内部参考电压典型值 }
  2. 非线性补偿

    // 二阶多项式补偿 float compensate_nonlinearity(float raw_temp, float a, float b) { return raw_temp + a * raw_temp + b * raw_temp * raw_temp; }
  3. 三线制引线补偿

    float compensate_lead_resistance(float measured_r, float lead_r) { return measured_r - lead_r; // 简单补偿模型 }

4. 完整实现代码与系统集成

4.1 模块化代码结构

建议将PT100测量功能封装为独立模块:

// pt100.h typedef struct { float temperature; float resistance; uint8_t status; // 0=OK, 1=开路, 2=短路 } PT100_Measurement; void PT100_Init(ADC_HandleTypeDef* adc, float vref, float gain); PT100_Measurement PT100_GetTemperature(void);
// pt100.c static ADC_HandleTypeDef* hadc_pt100; static float vref_pt100; static float gain_pt100; void PT100_Init(ADC_HandleTypeDef* adc, float vref, float gain) { hadc_pt100 = adc; vref_pt100 = vref; gain_pt100 = gain; } PT100_Measurement PT100_GetTemperature(void) { PT100_Measurement result = {0}; uint32_t adc_val = get_filtered_adc(hadc_pt100); // 检测开路/短路故障 if(adc_val < 10) { result.status = 1; // 开路 return result; } if(adc_val > 4090) { result.status = 2; // 短路 return result; } float voltage = adc_to_voltage(adc_val, vref_pt100); float resistance = calculate_pt100_resistance(voltage, vref_pt100, gain_pt100); result.resistance = resistance; result.temperature = resistance_to_temperature(resistance); result.status = 0; return result; }

4.2 温度校准实现

现场校准是提高测量精度的关键步骤:

typedef struct { float gain_correction; float offset_correction; } PT100_Calibration; PT100_Calibration pt100_cal = {1.0f, 0.0f}; void PT100_Calibrate(float known_temp) { PT100_Measurement m = PT100_GetTemperature(); if(m.status != 0) return; // 简单的一阶校准模型 float error = known_temp - m.temperature; pt100_cal.offset_correction += error; // 更新温度计算函数 m.temperature += pt100_cal.offset_correction; float gain_error = (known_temp - m.temperature) / m.temperature; pt100_cal.gain_correction *= (1.0f + gain_error); } float apply_calibration(float raw_temp) { return raw_temp * pt100_cal.gain_correction + pt100_cal.offset_correction; }

4.3 系统集成示例

将PT100测量集成到实际项目中:

// main.c int main(void) { HAL_Init(); SystemClock_Config(); ADC_HandleTypeDef hadc1; MX_ADC1_Init(&hadc1); float vref = calibrate_vref(&hadc1); PT100_Init(&hadc1, vref, 20.0f); while(1) { PT100_Measurement temp = PT100_GetTemperature(); if(temp.status == 0) { printf("Temperature: %.2f C\n", temp.temperature); } else { printf("Sensor error: %s\n", temp.status == 1 ? "Open circuit" : "Short circuit"); } HAL_Delay(1000); } }

5. 高级优化与故障排除

5.1 噪声抑制技术

在工业环境中,电磁干扰可能严重影响ADC测量精度。以下措施可显著改善信号质量:

  1. 硬件滤波

    • 在ADC输入引脚添加100nF陶瓷电容
    • 使用RC低通滤波(如1kΩ+100nF,截止频率≈1.6kHz)
  2. 软件技术

    // 改进的加权移动平均滤波 #define FILTER_WINDOW 8 float temp_history[FILTER_WINDOW]; float filtered_temp(float new_temp) { static uint8_t index = 0; temp_history[index] = new_temp; index = (index + 1) % FILTER_WINDOW; float sum = 0, weight_sum = 0; for(int i=0; i<FILTER_WINDOW; i++) { float weight = 1.0f / (1.0f + abs(i - index)); sum += temp_history[i] * weight; weight_sum += weight; } return sum / weight_sum; }

5.2 温度漂移补偿

环境温度变化会影响测量电路的性能,可通过以下方法补偿:

// 读取板载温度传感器(如有) float read_internal_temp_sensor() { ADC_ChannelConfTypeDef sConfig = {0}; sConfig.Channel = ADC_CHANNEL_TEMPSENSOR; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES; HAL_ADC_ConfigChannel(&hadc1, &sConfig); HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY); uint32_t adc_val = HAL_ADC_GetValue(&hadc1); // 转换为温度(公式因MCU型号而异) return ((float)adc_val * 3.3f / 4095.0f - 0.76f) / 0.0025f + 25.0f; } // 温度补偿函数 float compensate_temperature_drift(float raw_temp, float board_temp) { // 简化的补偿模型,参数需实际测试确定 return raw_temp + (board_temp - 25.0f) * 0.05f; }

5.3 常见故障诊断

故障现象可能原因排查方法
读数跳变大电源噪声检查电源滤波电容,示波器观察电源纹波
温度偏高运放增益误差重新校准增益参数
负温不准引线电阻影响检查是否为三线制接法,补偿引线电阻
ADC值饱和信号超出量程检查PT100是否短路,减小运放增益
无变化传感器开路检查PT100连接,测量回路电阻

在长时间运行的应用中,建议实现自动故障检测功能:

#define SHORT_THRESHOLD 50 // ADC值小于此视为短路 #define OPEN_THRESHOLD 4050 // ADC值大于此视为开路 uint8_t check_pt100_fault(uint32_t adc_val) { if(adc_val < SHORT_THRESHOLD) return 2; // 短路 if(adc_val > OPEN_THRESHOLD) return 1; // 开路 return 0; // 正常 }

掌握这些PT100测量技术后,你将能够根据具体应用需求灵活设计温度测量方案,不再受限于预封装模块的功能限制。无论是需要更高精度、更快响应还是更紧凑的系统集成,这套方法都能提供可靠的技术基础。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询