NTC 热敏电阻怎么测温度?查表法 + 二分查找 + 线性插值

📅 2026/7/11 12:21:00
NTC 热敏电阻怎么测温度?查表法 + 二分查找 + 线性插值
一句话: NTC 热敏电阻测温度最常用的方案——预存阻值-温度对照表ADC 采电压算出阻值二分查找定位区间线性插值算出最终温度。精度高、不占 Flash、跑得快。系列文章《嵌入式外设实战》 — NTC测温、SPI通信、I2C从机、定点数运算——外设驱动从入门到精通✅ 附完整代码 用文件柜抽屉讲透 用分和元讲透附代码 省引脚绝招 一张表讲清四种模式 多一根线差多远 电压不同的区别 用VTEC波动代替硬件信号 连续N次满足才算数 硬件脚悬空了也别慌 pid-feedforward-lookup when-to-drop-pid-d-term pid-deadzone-silence[TOC]适合谁读适合嵌入式开发者、单片机初学者及遇到类似问题的工程师信号链路一张图flowchart LR NTC[NTC热敏电阻] --|分压电路| ADC[ADC采样] ADC --|码值| R[算阻值] R --|二分查找| T[查表定位区间] T --|线性插值| OUT[输出温度]为什么不用公式直接算NTC 热敏电阻的阻值和温度是指数关系公式长这样R(T) R25 × e^(B × (1/T - 1/298.15))看着吓人。要在单片机上算这个公式需要浮点运算、指数函数慢且占 Flash。更关键的是——实际 NTC 不完全符合公式厂家给的阻值表才是准的。所以通用做法是厂家给什么表单片机就查什么表。电路怎么接最常见的分压电路VREF (基准电压, 比如 2.5V) │ ├── R_fixed (固定电阻, 比如 10KΩ 1%) │ ├──→ ADC 采样点 │ ├── NTC (热敏电阻) │ GNDADC 采到电压算 NTC 阻值/* * V_adc VREF × R_ntc / (R_fixed R_ntc) * * 反推: * R_ntc R_fixed × V_adc / (VREF - V_adc) * * 用 ADC 码值表示: * R_ntc R_fixed × adc_code / (adc_max - adc_code) */#define ADC_MAX 4095U /* 12-bit ADC */ #define R_FIXED 10000U /* 10KΩ 固定电阻 */ uint32_t ADC_to_Resistance(uint16_t u16AdcCode) { /* 防止除零 */ if (u16AdcCode ADC_MAX) { return 0xFFFFFFFFU; } if (u16AdcCode 0U) { return 0U; } /* R_ntc R_fixed × adc / (max - adc) */ return (uint32_t)R_FIXED * u16AdcCode / (ADC_MAX - u16AdcCode); }阻值-温度表厂家提供的典型数据以 MF55 103F3950 为例R2510KΩB3950/* 阻值-温度对照表 (部分) * 第一列: 阻值(Ω), 第二列: 温度(℃ × 10, 即 250 25.0°C) * 按阻值从大到小排列 (温度越低阻值越大) */ static const uint16_t s_au16NtcTable[][2] { { 33110, -200 }, /* 33110Ω → -20.0°C */ { 24900, -150 }, /* 24900Ω → -15.0°C */ { 18870, -100 }, /* 18870Ω → -10.0°C */ { 14380, -50 }, /* 14380Ω → -5.0°C */ { 11030, 0 }, /* 11030Ω → 0.0°C */ { 8510, 50 }, /* 8510Ω → 5.0°C */ { 6610, 100 }, /* 6610Ω → 10.0°C */ { 5170, 150 }, /* 5170Ω → 15.0°C */ { 4070, 200 }, /* 4070Ω → 20.0°C */ { 3220, 250 }, /* 3220Ω → 25.0°C */ { 2560, 300 }, /* 2560Ω → 30.0°C */ { 2050, 350 }, /* 2050Ω → 35.0°C */ { 1645, 400 }, /* 1645Ω → 40.0°C */ { 1330, 450 }, /* 1330Ω → 45.0°C */ { 1080, 500 }, /* 1080Ω → 50.0°C */ { 880, 550 }, /* 880Ω → 55.0°C */ }; #define NTC_TABLE_SIZE (sizeof(s_au16NtcTable) / sizeof(s_au16NtcTable[0]))实际使用时厂家数据手册里通常有 100-200 个点点越多精度越高。这里 16 个点只是示意。二分查找定位区间算出阻值后在表里找它落在哪两个点之间。因为表是按阻值从大到小排的用二分查找展开查看完整代码35行展开查看完整代码35行展开查看完整代码35行展开查看完整代码35行展开查看完整代码35行/* * 二分查找找到 R_ntc 在表中的位置 * 返回: 区间下标 iR_ntc 在 table[i] 和 table[i1] 之间 */ static uint8_t FindInterval(uint32_t u32Resistance) { uint8_t u8Low; uint8_t u8High; uint8_t u8Mid; /* 边界判断 */ if (u32Resistance s_au16NtcTable[0][0]) { return 0U; /* 比第一个还大 → 取第一个点 */ } u8Low 0U; u8High NTC_TABLE_SIZE - 1U; if (u32Resistance s_au16NtcTable[u8High][0]) { return u8High - 1U; /* 比最后一个还小 → 取最后一个区间 */ } /* 二分查找 */ while (u8Low u8High - 1U) { u8Mid (u8Low u8High) / 2U; if (u32Resistance s_au16NtcTable[u8Mid][0]) { u8High u8Mid; } else { u8Low u8Mid; } } return u8Low; /* R_ntc 在 table[low] 和 table[low1] 之间 */ }线性插值找到区间后在两点之间按比例算出温度展开查看完整代码38行展开查看完整代码38行展开查看完整代码38行展开查看完整代码38行展开查看完整代码38行/* * 线性插值: * temp T1 (R - R1) × (T2 - T1) / (R2 - R1) * * 所有值都放大 10 倍 (温度 ×10, 避免浮点) */ int16_t ADC_to_Temperature(uint16_t u16AdcCode) { uint32_t u32R; uint8_t u8Idx; int32_t i32Temp; uint32_t u32R1, u32R2; int32_t i32T1, i32T2; /* 1. ADC → 阻值 */ u32R ADC_to_Resistance(u16AdcCode); /* 2. 二分查找区间 */ u8Idx FindInterval(u32R); /* 3. 线性插值 */ u32R1 (uint32_t)s_au16NtcTable[u8Idx][0]; /* R1 (Ω) */ u32R2 (uint32_t)s_au16NtcTable[u8Idx 1U][0]; /* R2 (Ω) */ i32T1 (int32_t)(int16_t)s_au16NtcTable[u8Idx][1]; /* T1 (×10) */ i32T2 (int32_t)(int16_t)s_au16NtcTable[u8Idx 1U][1]; /* T2 (×10) */ /* * temp T1 (R - R1) × (T2 - T1) ÷ (R2 - R1) * * 注意: 阻值从大到小排R1 R2 * 所以 R - R1 ≤ 0, R2 - R1 0 * 先算分子再除分母避免丢失精度 */ i32Temp i32T1 (int32_t)(u32R - u32R1) * (i32T2 - i32T1) / (int32_t)(u32R2 - u32R1); return (int16_t)i32Temp; /* 返回值 ×10, 即 256 25.6°C */ }精度分析因素影响NTC 本身精度±1% 是常规水平固定电阻精度用 1% 的别用 5% 的表点数100-200 点基本够温度变化陡的区域可以多取几个点ADC 精度12-bit ADC, 4095 级, 精度约 0.1-0.2°C对大多数嵌入式应用来说查表法 ±0.5°C 以内的精度完全够用。完整调用/* 主循环每 100ms 调一次 */ void Monitor_Temperature(void) { uint16_t u16Adc; int16_t i16Temp; /* 读 ADC */ u16Adc ADC_Read(ADC_CH_NTC); /* ADC → 温度 (×10) */ i16Temp ADC_to_Temperature(u16Adc); /* 存到全局变量, 供其他地方用 */ g_i16Temperature i16Temp; /* 256 25.6°C */ }总结步骤做什么1. 电路VREF → 固定电阻 → ADC 采样点 → NTC → GND2. 算阻值ADC 码值 → 分压公式算出 R_ntc3. 查表二分查找阻值落在哪两个点之间4. 插值在两点间线性插值算出温度5. 防抖主循环周期调用不需要额外滤波三个知识点串成一条链路NTC 分压电路 → 二分查找 → 线性插值。搞懂这个温度采集就通了。实测对比浮点方案: 24次运算 ≈ 720条指令 | 定点查表方案: 24次运算 ≈ 48条指令CPU占用降低 93%有用的话点个收藏下次调试直接用。有问题欢迎评论区交流看到了都会回。下一篇用文件柜抽屉讲透——NTC测温、SPI通信、I2C从机、定点数运算——外设驱动从入门到精通