NTC 10K 热敏电阻测温补偿算法
NTC 热敏电阻广泛应用于嵌入式系统中。标称值为 10kΩ 的 NTC(常称'NTC 10K')凭借成本低、响应快、电路简单,成为温度测量的常用元件。但其阻值与温度呈非线性指数关系,直接换算误差较大,需通过软件算法进行补偿。
基础电路
典型 NTC 测温电路为分压器结构:
Vcc -- R_ref (10k) -- ADC Input
|
NTC (10k @ 25°C)
|
GND
MCU 采集电压后计算 NTC 阻值:
$$ R_{NTC} = R_{ref} \cdot \frac{V_{out}}{V_{cc} - V_{out}} $$
听起来挺直观对吧?可真正的挑战才刚刚开始——怎么把 $ R_{NTC} $ 变成准确的温度?
因为 NTC 的 R-T 曲线根本不是线性的!它是指数级的,低温区变化迅猛,高温区趋于平缓。如果你强行用一条直线去拟合,结果只会让你怀疑人生。
所以,必须上算法!而且得选对'武器'。
Steinhart-Hart 方程:精度王者
如果要评选'最准的 NTC 算法',那必须是 Steinhart-Hart 方程 :
$$ \frac{1}{T} = A + B \cdot \ln(R) + C \cdot (\ln(R))^3 $$
其中:
- $ T $ 是开尔文温度(K)
- $ R $ 是实测 NTC 阻值
- $ A, B, C $ 是材料系数,由厂商提供或三点标定得出
这套公式能在 -40°C 到 +125°C 范围内做到 ±0.1~0.5°C 的惊人精度,堪称工业级首选。
举个例子,某常见 10D-9 型号的参数可能是:
#define A 1.12915e-3
#define B 2.34124e-4
#define C 8.76741e-8
实现起来也不复杂:
#include <math.h>
float steinhart_hart(float r_ntc) {
float ln_r = log(r_ntc);
float inv_t = A + B * ln_r + C * pow(ln_r, 3);
float temp_k = 1.0 / inv_t;
return temp_k - 273.15f; // 转摄氏度
}
不过这里有个坑⚠️:很多低端 MCU 没有 FPU(浮点运算单元),跑 log() 和 pow() 会特别慢,甚至影响实时性。更糟的是,单精度浮点还容易累积截断误差。
✅ 所以建议:
- 高性能 MCU(如 STM32F4/F7)可用;
- 资源紧张时,考虑查表 + 插值替代;
- ABC 系数一定要针对具体型号实测标定,别照搬手册通用值!
Beta 模型:实用派首选
要是你觉得 Steinhart-Hart 太重了,那就试试它的轻量版—— Beta 参数模型 。它假设 C=0,只保留一次对数项,公式变得简洁多了:
$$ \frac{1}{T} = \frac{1}{T_0} + \frac{1}{\beta} \cdot \ln\left(\frac{R}{R_0}\right) $$
其中:
- $ R_0 = 10,000\Omega $(25°C 时的标称值)
- $ T_0 = 298.15K $
- $ \beta $ 是材料常数,典型值 3435~3950
代码写出来清爽得让人感动:
#define R0 10000.0f
#define T0 298.15f
#define BETA 3435.0f
float beta_model(float r_ntc) {
float inv_t = 1.0f / T0 + (1.0f / BETA) * logf(r_ntc / R0);
return (1.0f / inv_t) - 273.15f;
}
计算量只有 Steinhart-Hart 的一半左右,适合 STM8、PIC16 这类 8 位机。精度也能控制在 ±1°C以内 ,对于家电、电源模块完全够用。
当然也有缺点❌:在极端温度下(比如低于 -20°C 或高于 85°C)误差会明显增大。所以如果你做的是户外设备或者医疗产品,还是老老实实标定 Steinhart-Hart 吧。
查表法 + 线性插值:速度之王
再进一步,如果连 logf() 都不能忍?那就彻底抛弃数学函数,上 查表法 !
思路很简单:提前把几个关键温度点对应的 ADC 值存进数组,运行时找到最近的两个点,做个线性插值就行了。
比如这张简化的查找表:
| 温度 (°C) | R_NTC(Ω) | ADC 码值(12bit, 3.3V, 10k 上拉) |
|---|---|---|
| -40 | 298000 | 398 |
| -20 | 124000 | 726 |
| 0 | 57000 | 1165 |
| 25 | 10000 | 2048 |
| 50 | 3100 | 2860 |
| 75 | 1200 | 3450 |
| 100 | 500 | 3800 |
然后写个插值函数:
typedef struct {
uint16_t adc_val;
int8_t temp;
} TempPoint;
const TempPoint lookup_table[] = {
{ 398, -40 }, { 726, -20 }, { 1165, 0 }, { 2048, 25 }, { 2860, 50 }, { 3450, 75 }, { 3800, 100 }
};
int16_t table_interpolate(uint16_t adc_raw) {
if (adc_raw <= lookup_table[0].adc_val) return lookup_table[0].temp;
if (adc_raw >= lookup_table[TABLE_SIZE-1].adc_val) return lookup_table[TABLE_SIZE-1].temp;
for (int i = 0; i < TABLE_SIZE - 1; i++) {
if (adc_raw < lookup_table[i+1].adc_val) {
int16_t diff = lookup_table[i+1].adc_val - lookup_table[i].adc_val;
if (diff == 0) return lookup_table[i].temp;
int16_t frac = ((adc_raw - lookup_table[i].adc_val) * (lookup_table[i+1].temp - lookup_table[i].temp)) / diff;
return lookup_table[i].temp + frac;
}
}
return 0;
}
优点显而易见:
- ❌ 无浮点运算
- ⚡ 执行速度快(O(n),可优化为二分查找)
- 💾 内存可控(可根据精度增减表项)
非常适合恒温控制、过温报警这类需要快速响应的场景 👍。
分段线性拟合:折中高手
还有一种折中方案叫 分段线性拟合法 ——把整个温度区间切成几段,每段用一条直线逼近。
比如分成四段:
- [-40, -10]
- [-10, 30]
- [30, 70]
- [70, 125]
每段记录斜率 $ k $ 和截距 $ b $,满足: $$ T = k \cdot R + b $$
相比单一查表,少了搜索过程;相比完整非线性模型,又省了大量计算。属于那种'不极致但够用'的实用主义路线,在热水器、空调面板中很常见。
实际工程中的那些'坑'
光有算法还不够,实际部署时还得处理一堆现实问题。
自发热?关电源就行!
NTC 通电就会发热,尤其在低温时阻值极大(几十万欧姆),虽然电流小,但长时间工作仍可能导致自热偏差。
💡 解决办法超简单:用一个 GPIO 控制上拉电阻的供电,只在采样前打开,采完立刻关闭!
void measure_temperature() {
HAL_GPIO_WritePin(POWER_EN_PORT, POWER_EN_PIN, GPIO_PIN_SET); // 开电
HAL_Delay(10); // 等待稳定
uint32_t adc_val = read_adc();
HAL_GPIO_WritePin(POWER_EN_PORT, POWER_EN_PIN, GPIO_PIN_RESET); // 关电
float r_ntc = calculate_resistance(adc_val);
float temp = beta_model(r_ntc);
}
这一招能让平均功耗趋近于零,还能延长电池寿命,简直一举两得🔋。
ADC 分辨率不够怎么办?
10 位 ADC 在 3.3V 下每级约 3.2mV,对应温度变化可能差 0.5°C 以上。想要更细腻的感知?
✅ 几个提升手段:
- 换 12 位或更高 ADC(如 ADS1115)
- 使用外部基准电压(比 Vcc 更稳)
- 多次采样平均(oversampling),等效提升分辨率
PCB 布局也有讲究
长走线=天线,容易引入开关噪声。建议:
- NTC 尽量靠近 MCU
- 加 RC 滤波(例如 10k + 100nF)
- 地平面完整,远离 DC-DC 路径
回过头看,NTC 10K 之所以经久不衰,不只是因为它便宜,更是因为 软硬结合的设计智慧 。你可以用最便宜的传感器,搭配精心调校的算法,做出媲美数字传感器的性能。
未来趋势呢?AFE 专用芯片、AI 老化补偿、多传感器融合……都在路上。但在可预见的几年里,只要还有人在做电源、电机、家电、IoT 终端,NTC 10K + 补偿算法这套组合拳就不会退出舞台。
毕竟,有时候最'土'的方法,才是最可靠的 💪。

