热敏电阻测温实战:从原理到Arduino/CircuitPython代码实现

发布时间:2026/5/19 2:24:57

热敏电阻测温实战:从原理到Arduino/CircuitPython代码实现 1. 项目概述从电阻到温度的桥梁在嵌入式开发和电子DIY项目中温度测量是一个极其常见的需求。无论是环境监测、设备状态反馈还是简单的温控风扇你都需要一个可靠的“温度计”。市面上有琳琅满目的温度传感器从数字式的DS18B20、模拟式的LM35到高端的铂电阻和热电偶。但今天我想和你深入聊聊的是一个成本极低、结构简单却蕴含着不少设计巧思的经典元件热敏电阻。你可能在某个旧家电的电路板上见过它一个不起眼的小黑豆两根引线。它的全称是“热敏电阻”顾名思义就是对温度敏感的电阻。其核心价值在于它用极低的成本批量采购单价可低至几毛钱实现了相当不错的温度测量精度配合合适的电路和算法精度可达±0.25°C。这对于预算敏感、但对精度有一定要求的项目比如恒温孵化箱、3D打印机热床温度监测、或是简单的室内温湿度计是极具吸引力的选择。本文将以最常用的10K NTC负温度系数热敏电阻为核心手把手带你走通从原理认知、电路设计到Arduino和CircuitPython代码实现的完整路径。我们会深入探讨如何将电阻的变化转化为微控制器能理解的数字信号并利用Steinhart-Hart方程将原始数据换算成直观的温度值。更重要的是我会分享在实际调试中如何规避噪声干扰、优化读数精度以及如何根据你的具体应用场景做出最合适的设计权衡。无论你是刚接触模拟传感器的爱好者还是希望为产品寻找高性价比测温方案的工程师这篇文章都能提供扎实的参考。2. 热敏电阻核心原理与选型要点2.1 NTC与PTC两种截然不同的温度特性热敏电阻主要分为两大类NTC和PTC。它们的名字直接揭示了其特性。NTC负温度系数。随着温度升高其电阻值减小。这是我们用于温度测量的绝对主力。想象一下天气越热它对电流的“阻碍”反而越小。这种特性使得它在测温应用中非常直观电阻越小温度越高。PTC正温度系数。随着温度升高其电阻值增大。这种特性使其常被用作“自恢复保险丝”。当电路过流导致PTC发热时其电阻急剧增大从而限制电流保护后续电路故障排除后冷却电阻恢复电路自动接通。在纯粹的测温场景中我们很少使用PTC。为什么NTC更适合测温除了其电阻变化与温度呈良好的单调关系外更重要的是它在常温附近具有较高的灵敏度即每摄氏度电阻变化量大这使得微控制器的ADC能够分辨出细微的温度差异。2.2 关键参数解读不只是“10K”当你拿到一个标称“10K”的NTC热敏电阻时这个10K通常指的是它在25°C时的标称电阻值R25。但要想用好它还必须关注另一个核心参数B值。B值例如常见的3950描述了热敏电阻材料特性它定义了在两个特定温度点如25°C和50°C即B25/50之间电阻与温度关系的常数。B值越大意味着电阻随温度的变化率越大传感器在相同温度变化下的输出信号变化也更明显理论上灵敏度更高。此外还需留意精度常见的有1%、5%等。1%精度的热敏电阻在25°C时实际阻值可能在9.9K到10.1K之间。这个初始误差会直接影响测温的绝对精度但可以通过单点校准来补偿。热时间常数指热敏电阻响应环境温度变化63.2%所需的时间。这决定了传感器的响应速度。文中提到的15秒意味着它不适合测量快速变化的温度。工作温度范围注意区分元件本体和线材的耐温范围。例如一个热敏电阻本体可承受125°C但其PVC线材可能只能到105°C因此测量沸水100°C时需谨慎。注意购买热敏电阻时尽量向供应商索取对应的电阻-温度对照表或B值参数表。这是后续进行高精度温度换算的基础。如果只有B值我们可以使用简化公式如果有完整的表或更精确的Steinhart-Hart系数A, B, C则能获得更宽温度范围内更高的精度。2.3 热敏电阻的优劣权衡选择热敏电阻本质上是做一场权衡。它的优势非常突出成本极低是数字温度传感器如DS18B20价格的几分之一甚至更低。结构简单易于封装本质上就是一个电阻可以用环氧树脂、热缩管甚至防水胶轻松做成防水探头适用于潮湿或液体环境测量。接口简单仅需两根线无需特定通信协议任何带ADC的MCU都能读取。可靠性高无复杂集成电路耐冲击和电压波动能力强。但其劣势也需要在设计时充分考虑非线性电阻与温度是指数关系而非线性直接读取ADC值无法得到线性温度必须通过数学公式如Steinhart-Hart方程进行换算增加了软件复杂度。需要外部电路必须搭配一个精度较高的参考电阻组成分压电路参考电阻的精度和温漂也会影响整体精度。自热效应测量时流过热敏电阻的电流会产生热量导致自身温度略高于环境温度。对于高精度测量或静态空气测量此效应不可忽视。精度受限于ADC最终精度受微控制器ADC的分辨率和参考电压稳定性制约。3. 电路设计将电阻变化转换为电压信号微控制器如Arduino无法直接测量电阻它只能测量电压。因此我们的核心任务就是设计一个电路将热敏电阻的阻值变化线性地或者说可预测地转换为电压变化。最经典、最常用的方案就是分压电路。3.1 分压电路原理与计算电路连接非常简单将一个固定阻值的参考电阻通常与热敏电阻在25°C时的阻值相同这里用10KΩ与热敏电阻串联然后在它们中间引出连接点接到MCU的模拟输入引脚。Vcc (3.3V或5V) | [R_fixed] (10KΩ 参考电阻) | --- 连接到 MCU 模拟输入引脚 (A0) | [R_thermistor] (NTC热敏电阻) | GND根据欧姆定律和分压原理模拟输入引脚A0处的电压V_out为V_out Vcc * (R_thermistor / (R_fixed R_thermistor))从这个公式可以直观看出当温度升高R_thermistor减小V_out电压降低。当温度降低R_thermistor增大V_out电压升高。参考电阻选型的心得为什么通常选和热敏电阻标称值一样的阻值这主要是为了在中间温度点如25°C获得一半的Vcc电压使得ADC的动态范围得到最大化利用从而提高测量分辨率。如果测温范围偏高温可以适当减小参考电阻偏低温则可以增大。你可以用公式V_out Vcc * (R_ntc / (R_fixed R_ntc))结合热敏电阻在目标温度区间的阻值范围估算出V_out的范围确保它落在ADC的有效输入电压范围内通常是0-Vref并尽可能铺满。3.2 ADC读取与电阻值反算MCU的ADC会将V_out这个模拟电压转换为一个数字值。对于Arduino Uno10位ADC这个值在0到1023之间对于许多32位MCU如Arduino Zero、ESP32、CircuitPython支持的板子通常是12位或16位ADC范围可能是0-4095或0-65535。ADC的读数ADC_reading满足ADC_reading (V_out / V_ref) * (2^n - 1)其中V_ref是ADC的参考电压n是ADC的位数如10位。一个非常实用的技巧来了如果ADC的参考电压V_ref与电路供电电压Vcc相同那么Vcc和V_ref会在公式中约掉这意味着即使你的Vcc因为电池电量下降而略有波动只要它和V_ref同步变化就不会影响ADC读数相对于电阻的比例关系。这是使用分压电路的一个巨大优势。结合分压公式和ADC公式假设V_ref Vcc我们可以推导出热敏电阻的阻值R_thermistorR_thermistor R_fixed / ((ADC_max / ADC_reading) - 1)对于Arduino (10位ADCADC_max 1023)R_thermistor 10000 / ((1023.0 / ADC_reading) - 1)对于CircuitPython (16位ADCADC_max 65535)R_thermistor 10000 / ((65535.0 / ADC_reading) - 1)实操技巧公式验证。你可以在室温下用万用表测量热敏电阻的实际阻值同时运行读取ADC并反算电阻的代码对比两个结果。这是验证你电路连接和代码计算是否正确的最快方法。如果误差很大请检查参考电阻的精确值用万用表测并确认ADC参考电压设置。4. Arduino实战从代码到温度4.1 基础读取与电阻换算让我们从最基础的Arduino代码开始。首先我们只完成两件事读取ADC值并将其换算为热敏电阻的阻值。// 定义引脚和参考电阻值 #define THERMISTOR_PIN A0 #define SERIES_RESISTOR 10000 // 10K 参考电阻 void setup() { Serial.begin(9600); // 初始化串口用于输出结果 } void loop() { int adcValue analogRead(THERMISTOR_PIN); // 读取ADC值 Serial.print(ADC Reading: ); Serial.println(adcValue); // 将ADC值转换为电阻值 (针对10位ADC) float resistance SERIES_RESISTOR / ((1023.0 / adcValue) - 1); Serial.print(Thermistor Resistance: ); Serial.print(resistance); Serial.println( Ohm); Serial.println(-------------------); delay(1000); // 每秒读取一次 }上传这段代码打开串口监视器你应该能看到不断输出的ADC值和计算出的电阻值。用手捏住热敏电阻观察电阻值是否迅速下降因为你的体温加热了它。这是系统工作的第一个里程碑。4.2 精度提升技巧参考电压与软件滤波基础代码能工作但读数可能会跳动精度也不够。我们来引入两个非常有效的优化手段。1. 使用更稳定的参考电压Arduino Uno的默认ADC参考电压是板载的5V。这个5V通常来自USB或稳压芯片噪声可能较大。许多板子包括Uno提供了一个更干净的3.3V电源它通常经过二次稳压噪声更低。我们可以将3.3V连接到AREF引脚并设置ADC使用外部参考电压。硬件连接用一根杜邦线将板子的3.3V引脚连接到AREF引脚。代码修改在setup()函数中添加一行analogReference(EXTERNAL);。2. 软件均值滤波ADC读数会存在随机噪声。通过连续采样多次然后取平均值可以有效地平滑数据减少单次跳变的影响。#define THERMISTOR_PIN A0 #define SERIES_RESISTOR 10000 #define NUM_SAMPLES 10 // 采样次数可调整5-20 void setup() { Serial.begin(9600); analogReference(EXTERNAL); // 使用外部AREF接3.3V } void loop() { int adcValue 0; // 多次采样并累加 for (int i 0; i NUM_SAMPLES; i) { adcValue analogRead(THERMISTOR_PIN); delay(10); // 短暂延时避免采样过于密集 } adcValue / NUM_SAMPLES; // 计算平均值 float resistance SERIES_RESISTOR / ((1023.0 / adcValue) - 1); Serial.print(Avg ADC: ); Serial.print(adcValue); Serial.print( | Resistance: ); Serial.print(resistance); Serial.println( Ohm); delay(500); }注意事项analogReference(EXTERNAL);一旦被调用ADC将使用AREF引脚上的电压作为满量程基准。务必确保AREF引脚上的电压不超过板子允许的最大值通常是Vcc否则可能损坏ADC对于3.3V系统板如ESP32、Arduino Zero通常直接使用内部3.3V参考无需此操作。4.3 核心算法利用Steinhart-Hart方程计算温度得到电阻值后最关键的一步是将它转换为温度。我们需要一个模型来描述NTC热敏电阻的电阻-温度R-T关系。最精确的是Steinhart-Hart方程1/T A B * ln(R) C * [ln(R)]^3其中T是开尔文温度R是电阻A、B、C是元件特定的系数。但对于大多数应用尤其是温度范围不特别宽例如0-100°C时可以使用简化的B参数方程它是Steinhart-Hart方程在C0时的特例1/T 1/T0 (1/B) * ln(R/R0)T待求的热力学温度开尔文。R当前测量得到的电阻值。T0标称温度通常为25°C 298.15K。R0在标称温度T0下的电阻值即10K。B热敏电阻的B值即3950。ln自然对数。计算步骤计算R/R0。计算ln(R/R0)。计算1/T 1/T0 (1/B) * ln(R/R0)。计算T 1 / (1/T)得到开尔文温度。转换到摄氏度T_C T - 273.15。以下是整合了所有优化和温度计算的完整Arduino示例// 热敏电阻温度测量完整示例 #define THERMISTOR_PIN A0 #define SERIES_RESISTOR 10000.0 #define NOMINAL_RESISTANCE 10000.0 // R0: 25°C时的电阻 #define NOMINAL_TEMPERATURE 25.0 // T0: 标称温度摄氏度 #define B_COEFFICIENT 3950.0 // B值 #define NUM_SAMPLES 10 #define ADC_MAX 1023.0 void setup() { Serial.begin(115200); // 如果使用了外部AREF接3.3V取消下一行的注释 // analogReference(EXTERNAL); } void loop() { // 1. 采样并平均 int adcSum 0; for (int i 0; i NUM_SAMPLES; i) { adcSum analogRead(THERMISTOR_PIN); delay(10); } float adcAverage adcSum / (float)NUM_SAMPLES; // 2. 计算电阻 float resistance SERIES_RESISTOR / ((ADC_MAX / adcAverage) - 1.0); // 3. 使用B参数方程计算温度摄氏度 float steinhart; steinhart resistance / NOMINAL_RESISTANCE; // (R/R0) steinhart log(steinhart); // ln(R/R0) steinhart / B_COEFFICIENT; // 1/B * ln(R/R0) steinhart 1.0 / (NOMINAL_TEMPERATURE 273.15); // (1/T0) steinhart 1.0 / steinhart; // 求倒数得到开尔文温度 float temperatureC steinhart - 273.15; // 转换为摄氏度 // 4. 输出结果 Serial.print(ADC: ); Serial.print(adcAverage, 1); Serial.print( | R: ); Serial.print(resistance, 0); Serial.print( Ohm | Temp: ); Serial.print(temperatureC, 2); Serial.println( °C); delay(1000); }5. CircuitPython实战更简洁的嵌入式Python方案对于使用CircuitPython的开发板如Adafruit Feather M0/M4、RP2040系列等我们可以用Python代码实现相同的功能语法更加简洁直观。5.1 基础读取与计算首先确保你的板子已刷入CircuitPython固件。将热敏电阻和10K参考电阻按同样方式连接到板子的一个模拟输入引脚例如board.A1。在CircuitPython的交互环境REPL或code.py文件中可以这样操作import board import analogio import time import math # 初始化模拟输入 thermistor_pin analogio.AnalogIn(board.A1) # 参数定义 SERIES_RESISTOR 10000.0 NOMINAL_RESISTANCE 10000.0 NOMINAL_TEMPERATURE 25.0 B_COEFFICIENT 3950.0 ADC_MAX 65535.0 # CircuitPython ADC通常是16位 def read_temperature(): # 读取ADC值 adc_value thermistor_pin.value # 计算电阻 resistance SERIES_RESISTOR / ((ADC_MAX / adc_value) - 1.0) # B参数方程计算温度 steinhart math.log(resistance / NOMINAL_RESISTANCE) / B_COEFFICIENT steinhart 1.0 / (NOMINAL_TEMPERATURE 273.15) temperature_c (1.0 / steinhart) - 273.15 return temperature_c, resistance, adc_value while True: temp_c, r, adc read_temperature() print(fADC: {adc:6d} | R: {r:7.0f} Ohm | Temp: {temp_c:5.2f} °C) time.sleep(1.0)5.2 使用专用库简化流程CircuitPython生态的优势在于丰富的库。对于热敏电阻Adafruit提供了adafruit_thermistor库它封装了所有计算细节。首先你需要将adafruit_thermistor库文件通常是一个.mpy文件复制到你的CircuitPython设备的lib文件夹中。使用库的代码变得极其简洁import board import adafruit_thermistor import time # 初始化热敏电阻传感器 # 参数模拟引脚串联电阻标称电阻标称温度B值high_side接线方式 # 我们的电路是热敏电阻在下方接GND所以 high_sideFalse thermistor adafruit_thermistor.Thermistor( board.A1, series_resistor10000.0, nominal_resistance10000.0, nominal_temperature25.0, b_coefficient3950.0, high_sideFalse ) while True: temperature_c thermistor.temperature # 直接获取摄氏度温度 # 库内部也提供了原始电阻值属性如果需要 # resistance thermistor.resistance print(fTemperature: {temperature_c:.2f} °C) time.sleep(1.0)使用库的好处是避免了手动实现数学公式代码更健壮且库内部可能已经包含了一些优化如滤波。high_side参数是关键它定义了热敏电阻在分压电路中的位置。在我们的标准接法热敏电阻在下接GND中应设为False。如果接反了热敏电阻在上接VCC则需设为True。6. 精度分析与误差控制实战了解理论精度和实际能达到的精度是两回事。在实际项目中我们需要管理好误差来源。6.1 主要误差来源拆解热敏电阻自身误差通常由精度指标如1%决定。一个1%精度的10K热敏电阻在25°C时实际阻值可能在9.9K-10.1K之间。根据B参数方程推算这会导致约±0.25°C的初始温度误差。对策进行单点校准。在已知温度如室温用可靠温度计测量下读取计算出的温度计算出一个偏移量在后续读数中补偿。参考电阻误差分压电路中的那个10K固定电阻同样有精度常见为1%。其误差会直接传递到电阻计算中。对策使用精度更高如0.1%、低温漂的金属膜电阻。或者用万用表精确测量你实际使用的电阻值并在代码中使用这个实测值而不是标称值。ADC量化误差与噪声量化误差对于10位ADC1024级假设Vref5V每级代表约4.88mV。在25°C附近热敏电阻灵敏度约为-4.4%/°C电压变化率约为-0.22V/°C。因此ADC能分辨的最小温度变化约为 (4.88mV / 0.22V/°C) ≈ 0.022°C。理论上分辨率不错但噪声会淹没它。噪声电源噪声、数字电路干扰等会导致ADC读数波动。对策如前所述使用稳定的参考电压如板载3.3V、实施软件均值滤波、在模拟电源引脚加滤波电容如10uF电解并联0.1uF瓷片电容。自热误差流过热敏电阻的电流会使其发热。计算一下在5V供电两个10K电阻串联下电流I 5V / 20KΩ 0.25mA。热敏电阻消耗的功率P I² * R ≈ (0.00025²) * 10000 ≈ 0.000625W 0.625mW。这个功率很小但在静止空气中或对微小温度变化敏感的应用中仍可能引起0.1°C左右的温升。对策降低测量电流。可以增大串联电阻例如用47K或100K但会降低信号幅度。更好的方法是间歇供电将Vcc连接到一个GPIO引脚仅在测量时将该引脚设为高电平测量完毕设为低电平。这样平均功耗和自热效应可以大幅降低。6.2 校准与优化建议单点偏移校准在已知稳定温度T_actual下用你的系统测出温度T_measured。计算偏移量ΔT T_actual - T_measured。在后续所有读数中加上这个ΔT。这能消除热敏电阻、参考电阻的系统性偏差。两点斜率校准如果追求更高精度可以在两个已知温度点如冰水混合物0°C和沸水100°C进行测量拟合出实际的B值或Steinhart-Hart系数替换掉数据手册中的标称值。使用查找表对于MCU资源有限或要求快速计算的场景可以预先根据公式计算出每个ADC值对应的温度做成一个数组查找表。运行时直接通过ADC值索引获取温度省去了复杂的浮点对数运算尤其适合8位AVR单片机。选择更高分辨率的ADC许多现代MCU如ESP32、STM32、ATSAMD21内置12位甚至16位ADC能提供更精细的电压分辨直接提升系统分辨率和抗噪声能力。7. 常见问题与排查指南在实际焊接和调试中你可能会遇到以下问题。这里是一个快速排查清单现象可能原因排查步骤与解决方案读数完全不对如接近0或最大值电路连接错误引脚配置错误。1. 用万用表检查分压电路中间点的电压是否随温度变化在0-Vcc之间变动2. 检查代码中指定的模拟引脚是否正确。3. 检查参考电阻和热敏电阻是否接反、虚焊。读数不变化或变化很小热敏电阻损坏接触不良参考电阻值错误。1. 断电用万用表电阻档直接测量热敏电阻两端阻值用手加热看阻值是否显著下降。若无变化则损坏。2. 检查所有连接点是否焊牢。3. 确认代码中SERIES_RESISTOR的值与你实际使用的参考电阻一致。温度显示值漂移或跳动大ADC参考电压不稳定电源噪声大未滤波。1. 尝试使用analogReference(EXTERNAL)并连接稳定的3.3V到AREF。2. 在板子的Vcc和GND之间靠近模拟部分并联一个10uF电解电容和一个0.1uF瓷片电容。3. 在代码中增加均值滤波的采样次数NUM_SAMPLES。4. 检查是否有多余的线缆靠近模拟线路引入干扰。计算出的温度值明显偏高或偏低B值或标称电阻参数错误需要校准。1. 核对热敏电阻数据手册确认B值和R25值是否正确输入代码。2. 进行单点偏移校准在稳定室温下用一个可信的温度计测实际温度与系统读数对比计算并补偿偏移量。加热后温度读数反而下降误用了PTC热敏电阻或电路接反。确认你使用的是NTC热敏电阻。检查电路是否是热敏电阻接在下方靠近GND如果是则温度升高电阻减小分压点电压降低ADC值减小计算出的温度应升高。如果相反请检查公式中电阻计算的分子分母是否正确。在CircuitPython中读数异常high_side参数设置错误库未正确安装。确认你的电路接法。如果热敏电阻在下方接GND则初始化时high_sideFalse。如果在上方接VCC则high_sideTrue。确保adafruit_thermistor.mpy文件已放在设备的lib文件夹内。最后分享一个我个人的实操心得对于长期运行的温度监测项目间歇供电是提升稳定性和降低自热误差的利器。它不仅省电还能让热敏电阻在大部分时间处于“冷却”状态测量时更能反映真实环境温度。实现起来只需多用一个GPIO口控制分压电路的上电成本增加极少但收益明显。

相关新闻