ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

PT100+LM358+STM32温度采集电路设计:从电桥计算到ADC反算全流程

PT100+LM358+STM32温度采集电路设计:从电桥计算到ADC反算全流程 做温度采集的项目我发现很多人一开始会纠结选型DS18B20确实简单但精度和稳定性在工业场景不够看热电偶能测高温但信号是毫伏级还得做冷端补偿对新手不太友好。PT100铂电阻是另一个思路——阻值变化线性度好0℃时100Ω测个几百度没问题而且中低温段精度明显比热电偶靠谱。再配上LM358把信号放大送到STM32的ADC采集这套方案我用了好几年成本低、够用、可复制。这篇文章就是把整个链路——从电桥计算到运放增益再到ADC反算温度——全部摊开讲清楚里面每一步都有完整计算过程可以照着抄。适合看这篇文章的朋友正在做毕业设计要搭测温电路的同学或者产品里需要低成本温度采集、又不想一上来就上专用温度芯片的嵌入式工程师。我把PT100的非线性、LM358的失调电压、电桥电阻的匹配误差这些坑都踩过一遍文末也会给出对应的排查和校准方法尽量让你一次就把电路调明白。1. 方案选型为什么偏偏是 PT100 LM358 STM32 ADC1.1 几种测温方案的对比先说结论没有绝对最好的传感器只有最合适当前场景的组合。我把常见方案放在一起对比过优劣势非常明显方案测温范围输出形式线性度成本典型痛点NTC 热敏电阻-40~150℃电阻变化较差强非线性很低批次一致性差需要查表或多项式拟合DS18B20-55~125℃数字单总线-低测温范围窄响应慢高温环境可靠性一般热电偶-200~1300℃毫伏电压中等低冷端补偿麻烦信号微弱干扰敏感PT100-200~850℃电阻变化较好中阻值变化幅度小需要放大电路专用数字温度芯片视型号I2C/SPI-中高成本高探头形状和布线不够灵活我选择PT100的核心原因有三个。第一它的阻值-温度关系在0~300℃范围内比较接近线性哪怕不做复杂拟合用一个二次多项式也能把误差压到0.3℃以内第二铂电阻的长期稳定性是热敏电阻比不了的同样是100℃环境跑一个月后铂电阻飘移很小NTC可能都换了几个百分点第三PT100探头从几块钱的贴片封装到几十块钱的铠装探头都有机械强度和耐温能力可以根据现场工况随便挑。1.2 为什么不用专门的仪表放大器市面上有INA128、AD620这类精密仪表放大器一个芯片十几块到几十块不等增益精度和共模抑制比确实比LM358好。但在很多低成本项目里尤其是个位数成本敏感的消费级设备仪表放大器会被第一个砍掉。LM358单价不到一块钱内部有两个独立运放一个用来做信号放大另一个还能做电压跟随或恒流源非常实用。LM358最大的不足是失调电压和温漂。它的输入失调电压典型值2mV最大能到7mV放在需要放大几十倍微弱信号的场景这个误差会被一起放大。不过针对PT100测温这种应用我们有一个很现实的处理思路先接受这个误差然后通过软件做两点标定把系统偏差拉回来。实际测试下来在0~200℃范围内校准后的系统误差可以控制在±1℃以内很多项目完全够用。2. 硬件电路电桥、放大、ADC 的完整计算2.1 惠斯通电桥设计核心公式与阻值选型PT100的本质是电阻值随温度变化而单片机只能采集电压。所以第一步要把电阻变化转换成电压变化这里最经典的电路就是惠斯通电桥。电桥的好处是能把一个微小的电阻差值转换为差分电压同时抵消一部分供电电压波动的影响。我的常见接法是这样的R1 1kΩ1%精度就行R2 1kΩ1%精度R3 100Ω这里建议用0.1%精度的金属膜电阻第四臂接PT100阻值记为 Rt电桥电源直接取STM32开发板的3.3V记为 Vs。两个分压点的电压分别是Va Vs × Rt / (R1 Rt)Vb Vs × R3 / (R2 R3)在0℃时PT100的阻值正好是100Ω如果R3也是100Ω那么电桥就是完全平衡的Va Vb。随着温度升高Rt增大Va升高Vb保持不变两者之差就是我们需要放大的信号。这个设计里R1和R2选1kΩ而不是100Ω是经过考虑的。如果把R1选成100Ω电桥电流会达到16.5mAPT100自身发热严重会造成测量偏差R1取1kΩ后电流降到1.5mA自热效应基本可以忽略。R3取100Ω是为了在0℃时让电桥平衡这里的精度直接影响零点所以R3我坚持用0.1%精度。2.2 LM358 差分放大电路增益计算电桥输出的差分电压其实很小。以0~300℃量程为例300℃时PT100阻值约为212.05Ω此时Va 3.3 × 212.05 / (1000 212.05) ≈ 0.577VVb 3.3 × 100 / (1000 100) 0.300V差分电压只有0.277V。如果直接送ADC12位分辨率下只有约344个码值跳动太浪费量程了。所以必须放大。我用LM358接成标准差分放大电路电阻取值如下反相输入端通过 Rg1 10kΩ 接到 Vb同相输入端通过 Rg2 10kΩ 接到 Va同相输入端另接 Rg3 10kΩ 到GND反相输入端与输出之间接 Rf 100kΩ这种情况下增益为Gain Rf / Rg 100k / 10k 10倍满量程输出电压 0.277V × 10 2.77V距离3.3V还有约0.53V的余量。这个余量是故意的因为LM358输出并不是真正的轨到轨如果增益再往上加到12倍满量程输出超过3V一方面会让运放进入非线性区另一方面当PT100温度略超300℃时信号会被削顶读数反而不可信。留出10%~15%的余量是工程上的基本习惯。我还要特别强调一点差分放大电路的性能很大程度上由电阻匹配精度决定。Rf/Rg1 和 Rg2/Rg3 这两组的比值如果不一致共模抑制比会大幅下降。所以这四个电阻我都用0.1%精度其中Rg2和Rg3选同批次同一阻值尽量保证比例一致。2.3 供电与 ADC 接口设计的几个细节LM358是单电源运放工作电压范围很宽3~32V都能工作。在这个电路里如果直接用3.3V给运放供电输出摆幅的上限会被限制在2V左右满量程会损失不少所以我选择用5V给LM358供电输出范围0~3.5V放大器输出最大2.77V完全在安全区间内。运放输出直接连到STM32的ADC引脚之前我习惯串一个1kΩ的限流电阻再对地并一个100nF的电容构成一阶低通滤波。这个100nF电容的截止频率大约是1.6kHz能滤掉大部分高频干扰限流电阻则能保护ADC引脚防止运放异常时输出过压损坏单片机。电源去耦也要特别注意。LM358的电源引脚处我放了两个电容一个10μF钽电容稳住低频一个100nF陶瓷电容滤高频。3.3V电桥电源如果直接取自STM32的3.3V输出ADC采样时会受到芯片内部数字电路开关噪声的影响所以我建议电桥电源用独立的LDO输出或者至少并联一个100μF电容稳定电压。2.4 改进版电路用 LM358 的第二个运放做跟随器LM358内部有两个运放上面只用了其中一个另一个也不要浪费。在实际测试中我发现单运放差分放大电路的输入阻抗并不高尤其是反相输入端从Vb信号源看进去大约只等效于10kΩ虽然对电桥影响不算大但如果你使用更长的PT100引线或者电桥内阻更大的场景就会带来额外误差。我的改进方案是这样用第二个运放接成电压跟随器接在Va和差分放大电路的同相输入端之间。相当于先把电桥的分压信号做一次阻抗变换再用经过缓冲的低阻抗信号去驱动差分放大器。这样做的好处是同相输入端不需要再经过Rg2分压直接接入缓冲后的信号输入阻抗大幅提高差分放大电路的增益公式也更好控制。当然这个方案需要重新调整差分放大器的输入端接法但工程上很值得尤其是当电桥输出阻抗比较高或者线路比较长的时候效果很明显。3. STM32 侧ADC 配置、采样与滤波3.1 引脚分配与 ADC 初始化代码STM32的ADC引脚有很多我用的是PA0作为模拟输入。电源和地线的处理上VDDA和VREF引脚要外接一个10μF和一个100nF电容VREF直接接3.3V电桥的3.3V最好从同一个电压源取这样能保证ADC参考电压和信号电压是同源的测量误差会小很多。初始化代码以STM32F103标准库为例void ADC_Init_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 72MHz / 6 12MHz GPIO_InitStructure.GPIO_Pin GPIO_Pin_0; GPIO_InitStructure.GPIO_Mode GPIO_Mode_AN; GPIO_InitStructure.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA, GPIO_InitStructure); ADC_DeInit(ADC1); 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; ADC_Init(ADC1, ADC_InitStructure); ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5); ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); while (ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); while (ADC_GetCalibrationStatus(ADC1)); }校准寄存器是STM32出厂时烧录好的运行ADC_ResetCalibration和StartCalibration两个步骤可以纠正芯片内部的增益和偏移误差这一步不能省。3.2 采样时间、通道阻抗与抗混叠STM32 ADC的采样时间是一个经常被忽略的参数。ADC内部采样电容需要充电时间如果信号源阻抗太高而采样时间太短电容还没充到稳定电压就被采走了结果会偏低。常规配置里采样周期有1.5、7.5、13.5、28.5、41.5、71.5、239.5个ADC时钟周期可选。LM358运放输出阻抗很低理论上即使短采样时间也能驱动采样电容。但我还是习惯把采样时间设置为最长的239.5个周期。原因很简单测温信号本身变化缓慢不需要高频采样长采样时间能做内部低通滤波对抑制50Hz工频干扰和随机噪声有帮助。我这套配置ADC时钟12MHz239.5个周期对应约20μs的采样时间配合每次转换前软件触发一个点采下来大约22μs。如果开启连续转换模式每秒能采4万多次对测温应用来说绰绰有余余量可以用来做多次平均滤波。3.3 C 语言实现的高效滤波LM358放大后的信号进入ADC后会叠加噪声。噪声来源很多电桥供电的纹波、运放自身噪声、空间电磁干扰。即便加了RC低通滤波ADC读数依然会上下跳动几个码值。对于测温这种慢变量最实用的办法就是软件滤波。我常用的滑动平均滤波器只需要一个固定长度数组每次新采样值覆盖最旧的值然后求平均代码如下#define ADC_FILTER_LEN 16 static uint16_t adc_buf[ADC_FILTER_LEN]; static uint8_t adc_idx 0; static uint32_t adc_sum 0; uint16_t adc_filter_push(uint16_t val) { adc_sum - adc_buf[adc_idx]; adc_buf[adc_idx] val; adc_sum val; adc_idx (adc_idx 1) % ADC_FILTER_LEN; return (uint16_t)(adc_sum / ADC_FILTER_LEN); }滑动平均对高斯白噪声的抑制效果很好16次平均可以降低约12dB噪声。如果想要更强的抗脉冲能力可以先用中值滤波剔除异常点再用滑动平均平滑两层滤波配合能应付绝大多数工业现场。4. 从 ADC 值到温度反算公式与标定4.1 PT100 阻值-温度关系CVD 方程与查表法PT100的阻值-温度关系不是绝对线性0℃以上可以用Callendar-Van Dusen方程描述Rt R0 × (1 A×t B×t²)其中R0100ΩA3.9083e-3B-5.775e-7。在0~300℃范围内这个公式的误差可以忽略不计完全够用。如果不想在单片机里做浮点二次方程求解也可以直接用分度表查表法。我把PT100分度表以数组形式烧录到Flash里用二分法查表就能在几百微秒内找到对应温度。查表法的好处是一劳永逸而且天然处理非线性缺点是占用几百字节Flash但STM32的Flash通常够大这个成本可以接受。4.2 完整反算流程与代码实现从ADC值反算温度最严谨的做法是把整个链路逆推回去ADC值 → 输出电压 → 放大前差分电压 → 电桥Va电压 → PT100阻值 → 查表/公式 → 温度每一步都有明确的公式我直接给出实现代码#define VREF 3.3f #define GAIN 10.0f #define R_TOP 1000.0f #define R3 100.0f float adc_to_temp(uint16_t adc_val) { float vout, vdiff, vb, va, rt, t; float A 3.9083e-3f; float B -5.775e-7f; // 1. ADC值转电压 vout (float)adc_val / 4095.0f * VREF; // 2. 除以运放增益还原电桥差分电压 vdiff vout / GAIN; // 3. Vb固定值为 R3/(R_TOPR3)*VREF vb VREF * R3 / (R_TOP R3); // 4. Va Vb 差分电压 va vb vdiff; // 5. 由 Va VREF * Rt / (R_TOP Rt) 反推 Rt rt R_TOP * va / (VREF - va); // 6. CVD方程反解温度二次方程取正根 float c 1.0f - rt / 100.0f; float disc A*A - 4.0f * B * c; if (disc 0.0f) return -999.0f; t (-A sqrtf(disc)) / (2.0f * B); return t; }用这个函数在0℃附近测试ADC每变化1个码值对应的温度大约是0.08℃也就是说理论分辨率能到0.1℃以内。不过实际中受供电纹波、电阻精度和运放失调影响系统有效分辨率大概在0.2~0.3℃。4.3 两点标定法与误差测试前面我反复强调LM358失调会导致零点偏移这不能靠换高端运放硬扛软件标定是最经济的做法。具体流程并不复杂准备冰水混合物和沸水两个恒温源分别记录系统输出的ADC值。0℃冰水混合物按标准大气压下冰水共存温度等待温度稳定5分钟记录ADC值ADC_0100℃沸水当地沸点有偏差时最好用标准温度计实测记录ADC值ADC_100然后得到线性修正系数scale (ADC_100 - ADC_0) / 100.0f最终温度t_corrected (adc_now - ADC_0) / scale这个两步标定法可以同时抵消掉运放失调电压、电阻精度误差、供电电压偏差等系统误差实测下来0~100℃区间内的误差能控制在±0.5℃以内。我这里还测了一组数据供参考标准温度标定前计算值标定后计算值0℃-3.2℃0.1℃25℃22.1℃24.8℃50℃47.6℃50.2℃75℃72.3℃74.9℃100℃96.8℃100.1℃标定前的误差主要来自运放失调和电桥电阻精度。标定后整体误差压缩到0.3℃以内满足大多数工业采集需求。5. 常见问题与排查实录5.1 读数上下乱跳不稳定这个现象我在第一版电路上遇到过。最初以为运放的问题后来示波器一量发现LM358输出根本不稳。原因出在3.3V电桥电源上STM32板载LDO输出噪声很大电桥电源纹波被放大器放大后直接叠加到ADC。解决办法电桥供电不要直接从板载3.3V拉改用单独的线性稳压芯片或者至少加一个100μF电容滤波。同时在ADC引脚加RC低通滤波软件里再配上滑动平均三层防护下来ADC读数基本能稳定在两个码值以内。5.2 0℃时输出不是 0V零点漂移这是LM358方案最典型的坑。用万用表测运放输出0℃时理论应该是0V实际可能测出几十甚至上百毫伏。原因有三层运放失调电压、电桥电阻误差、R3不是标准100Ω。解决方法不是追求硬件绝对零位而是接受这个偏移量然后做软件校准。在0℃时记录下ADC值作为偏移常量之后每次采样都先减掉这个偏移值再算温度。这个思路不仅简单而且能同时修正多个硬件误差源。5.3 放大输出到不了满量程如果换用3.3V给LM358供电你会发现在温度较高时输出电压卡在2V左右不再增长这是LM358输出级晶体管饱和压降造成的。LM358并非轨到轨输出运放当负载较重时其输出最高只能到电源电压减1.5V左右。所以我在设计里特意让LM358用5V供电即便温度到300℃输出也只有2.77V离饱和区很远。如果你非要3.3V供电建议把放大倍数降到8倍牺牲一部分分辨率换取消顶的安全距离。5.4 如何在低成本下把精度再提高一个档次在现有方案基础上想再提精度可以从几个维度下手。第一把电桥的R1和R2换成0.1%精密电阻这能明显改善电桥的平衡度第二电桥电源和ADC参考电压改为同一个外部基准芯片输出比如REF3033这样电源波动带来的误差会大幅减小第三软件里做三阶多项式拟合PT100的非线性而不是只靠CVD二次方程第四如果你需要测很远距离的PT100务必用三线制接法补偿引线电阻的影响。这些都是小成本大效果的优化比直接换仪表放大器更划算。最后的小技巧根据我反复调这块电路的经验有个容易忽略但影响很大的细节电路板上电桥部分的GND走线一定要单独拉回电源负极不要和数字芯片的回流地混在一起。运放放大的信号本身只有零点几伏地上的几十毫伏噪声就足以让温度读数产生严重误差。用星型接地把模拟部分和数字部分分开是我测过改善最明显的一个布局改动。另外焊接好电路后先别急着接PT100用标准电阻箱模拟100Ω和138.51Ω可以先不依赖温度源就能把整个测量链路调试到精准状态这个方法很适合排错和批量调试。
返回列表