STM32F103与NTC热敏电阻测温系统设计与优化

STM32F103与NTC热敏电阻测温系统设计与优化

1. STM32F103与NTC热敏电阻测温系统概述

在工业控制、家电温控和物联网设备中,温度监测是最基础也最关键的环节之一。相比昂贵的数字温度传感器,NTC热敏电阻凭借其高灵敏度(典型值±1%)、快速响应(毫秒级)和极低成本(单价低于0.5元)的优势,成为大批量应用的理想选择。以MF52-103/3950这款10KΩ B值为3950的热敏电阻为例,其工作温度范围可达-40℃~125℃,完全覆盖常规应用场景。

STM32F103C8T6作为意法半导体的经典Cortex-M3内核MCU,内置12位ADC(0~3.3V量程)和丰富的外设资源,与NTC构成测温系统时具有天然优势:

  • 硬件成本极低:仅需MCU、NTC和普通贴片电阻各1个
  • 开发便捷:利用CubeMX可快速配置ADC通道
  • 精度适中:经软件补偿后可达±0.5℃级精度

典型接线方案中,NTC与10KΩ精密电阻(±1%)组成分压电路,MCU的ADC引脚连接至分压中点。当环境温度变化时,NTC阻值改变导致分压比变化,ADC采集电压值后通过B值公式换算为温度值。

关键提示:B3950表示材料常数,该值直接影响温度计算公式的选择。不同B值的NTC绝不能混用计算公式,否则会产生系统性误差。

2. 硬件电路设计与元器件选型

2.1 NTC热敏电阻特性解析

MF52-10K-B3950作为直径仅2mm的环氧包封型NTC,其核心参数需要开发者透彻理解:

  • 标称阻值:25℃时为10KΩ(即R25=10K)
  • B值:3950K(25℃~50℃区间)
  • 耗散系数:约2.5mW/℃(自热效应影响)
  • 热时间常数:≤7秒(液体中)

实际应用时需特别注意非线性特性。以10KΩ B3950为例,其阻值-温度曲线呈现明显指数特征:

  • 0℃时阻值≈32.6KΩ
  • 25℃时阻值=10KΩ
  • 50℃时阻值≈3.6KΩ
  • 100℃时阻值≈0.7KΩ

2.2 分压电路设计要点

推荐采用经典分压电路设计,关键参数计算如下:

  1. 上拉电阻选择

    • 理想值应与NTC在测量中点温度时的阻值相近
    • 对于10KΩ B3950测量0~100℃范围,建议选用10KΩ±1%精度金属膜电阻
    • 功率计算:假设VCC=3.3V,最大功耗发生在低温(高阻值)时: $$ P_{max} = \frac{V_{CC}^2}{R_{NTC}+R_{上拉}} = \frac{3.3^2}{32.6K+10K} ≈ 0.23mW $$
  2. 滤波电路设计

    • 在ADC输入端增加100nF陶瓷电容
    • 必要时可串联100Ω电阻形成RC滤波
  3. 布线注意事项

    • NTC应远离MCU等发热元件
    • 走线尽量短以减少干扰
    • 避免将NTC安装在PCB发热器件上风口

2.3 STM32F103 ADC配置

通过CubeMX配置ADC时需关注以下参数:

ADC_InitTypeDef ADC_InitStructure; ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 独立模式 ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 单通道 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 连续转换 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; // 软件触发 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; // 数据右对齐 ADC_InitStructure.ADC_NbrOfChannel = 1; // 1个通道 ADC_Init(ADC1, &ADC_InitStructure); // 设置采样时间(关键!) ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);

经验分享:采样时间建议设置为239.5周期(约17.2μs@14MHz),过短的采样时间会导致ADC读数波动较大。实测在12位分辨率下,延长采样时间可使读数波动范围从±5LSB降至±1LSB。

3. 温度换算算法实现

3.1 B值公式推导

NTC的电阻-温度关系遵循Steinhart-Hart方程简化版: $$ \frac{1}{T} = \frac{1}{T_0} + \frac{1}{B} \ln(\frac{R}{R_0}) $$

其中:

  • T:当前温度(单位开尔文)
  • T0:参考温度(通常取298.15K,即25℃)
  • R:当前NTC阻值
  • R0:参考温度下的阻值(10KΩ)
  • B:材料常数(3950K)

根据分压原理,ADC采集的电压Vadc与NTC阻值关系为: $$ R_{NTC} = R_{上拉} \times (\frac{V_{CC}}{V_{adc}} - 1) $$

3.2 代码实现优化

避免浮点运算的定点数实现方案:

#define B_CONST 3950.0f #define R_NOMINAL 10000.0f #define T_NOMINAL 298.15f float Read_Temperature(void) { uint16_t adc_value = Get_ADC_Value(); // 获取ADC原始值 float voltage = adc_value * 3.3f / 4095.0f; float r_ntc = 10000.0f * (3.3f / voltage - 1.0f); // Steinhart-Hart方程计算 float steinhart; steinhart = r_ntc / R_NOMINAL; // (R/R0) steinhart = log(steinhart); // ln(R/R0) steinhart /= B_CONST; // 1/B * ln(R/R0) steinhart += 1.0 / T_NOMINAL; // + (1/T0) steinhart = 1.0 / steinhart; // 取倒数 steinhart -= 273.15; // 开尔文转摄氏度 return steinhart; }

性能优化技巧:在RAM充足的STM32F103上,可预先计算0-100℃对应的ADC值建立查找表,将浮点运算转换为查表+线性插值,速度可提升10倍以上。

3.3 软件滤波处理

针对ADC采集的噪声,推荐采用复合滤波策略:

  1. 硬件级:每次采样间隔加入1ms延时
  2. 软件级
    • 移动平均滤波:连续采样8次取平均
    • 中值滤波:剔除明显异常值
    • 一阶滞后滤波:对快速波动进行平滑
#define FILTER_LEN 8 uint16_t adc_filter_buf[FILTER_LEN]; float Get_Filtered_ADC(void) { static uint8_t index = 0; uint32_t sum = 0; // 采集新值并存入环形缓冲区 adc_filter_buf[index] = ADC_GetValue(); index = (index + 1) % FILTER_LEN; // 计算移动平均 for(uint8_t i=0; i<FILTER_LEN; i++) { sum += adc_filter_buf[i]; } return (float)sum / FILTER_LEN; }

4. 系统校准与误差补偿

4.1 两点校准法实操

即使使用高精度电阻,实际系统仍可能存在误差,推荐采用两点校准:

  1. 冰水混合物校准(0℃点)

    • 将NTC插入冰水混合物(确保完全浸没)
    • 等待5分钟达到热平衡
    • 记录ADC读数AD0
    • 计算理论电阻值:R0_cal = 32650Ω(查B3950表)
  2. 沸水校准(100℃点)

    • 将NTC插入沸腾蒸馏水(注意安全)
    • 记录ADC读数AD100
    • 计算理论电阻值:R100_cal = 670Ω
  3. 校准参数计算

// 计算实际分压电阻值 float R_up_actual = (AD100 * 32650 - AD0 * 670) / (AD0 - AD100); // 更新计算公式中的上拉电阻值 #define R_UPDATED R_up_actual

4.2 常见误差源分析

误差类型影响程度补偿方法
ADC量化误差±0.5℃软件滤波
分压电阻精度±1℃使用0.1%精度电阻
B值偏差±2℃两点校准
自热效应±0.3℃降低工作电流
导线电阻±0.2℃四线制测量

4.3 长距离传输方案

当NTC与MCU距离超过1米时,需特别处理:

  1. 四线制接法
    • 使用双绞线传输
    • 单独走线提供激励电压
    • 另一对线测量分压电压
  2. 电流源方案
    • 改用恒流源驱动NTC
    • 通过测量端电压计算电阻
  3. 数字传输方案
    • 在NTC端放置廉价MCU(如STM8)
    • 通过UART或PWM传数字信号

5. 进阶应用与性能提升

5.1 多通道温度监测

利用STM32F103的16通道ADC,可实现多路温度监测:

// CubeMX配置多通道扫描模式 ADC_InitStructure.ADC_ScanConvMode = ENABLE; ADC_InitStructure.ADC_NbrOfChannel = 4; // 4个NTC通道 // DMA配置(提升效率) DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adc_results; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 4; DMA_Init(DMA1_Channel1, &DMA_InitStructure); // 启动DMA ADC_DMACmd(ADC1, ENABLE);

5.2 低功耗设计技巧

对于电池供电设备:

  1. 间歇工作模式:
    • 每60秒唤醒一次
    • 开启ADC测量
    • 完成后进入STOP模式
  2. 优化电路参数:
    • 增大上拉电阻至100KΩ
    • 缩短ADC采样时间
  3. 代码实现:
void Enter_LowPower(void) { ADC_Cmd(ADC1, DISABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入省电 PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI); SystemInit(); // 唤醒后需重新初始化时钟 }

5.3 无线传输集成

结合JDY-31蓝牙模块实现温度数据无线传输:

  1. 硬件连接:
    • TXD接STM32的PA10(USART1_RX)
    • RXD接PA9(USART1_TX)
    • VCC接3.3V
  2. 软件配置:
USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_Init(USART1, &USART_InitStructure); void Send_Temp_Data(float temp) { char buf[32]; sprintf(buf, "TEMP:%.1fC\r\n", temp); for(int i=0; i<strlen(buf); i++) { USART_SendData(USART1, buf[i]); while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); } }

实测发现,完整系统(STM32F103+JDY-31+NTC)在连续工作模式下电流约12mA,若采用1分钟间隔的间歇工作模式,平均电流可降至0.5mA以下,使用2000mAh的CR2032电池可维持近6个月工作。