1. 项目缘起与整体设计思路温度监测这件事听起来像是电子入门的第一课但真正落到工业级嵌入式和暖通空调HVAC场景里坑远比想象中多。我最近在做一个机房环境监控的小项目需求很明确既要能测本地机柜进风口的温度又要能通过远程探头监测风管或远端房间的温度而且两路数据要能实时上报、超限告警。选来选去主控定了 STM32F031C6温度传感用了 PJ85718DM。这套组合不是拍脑袋定的背后有一整套关于精度、成本、接口和可靠性的权衡。先说这个项目的核心目标。它要解决的是“本地远程”双点温度采集的问题。本地温度通常指设备自身所处环境的温度比如机柜内部、控制箱里面远程温度则是通过延长线把传感器引到几米甚至十几米外的地方去测风管、水管或者另一个房间的温度。HVAC 场景里这种需求特别典型——空调回风口和送风口要分别测温或者一个控制器要同时管室内和室外两个测点。传统做法是每个测点配一个独立变送器成本高、布线乱而用一颗 MCU 带两路温度传感器就能把采集、处理、通信全包了。为什么主控选 STM32F031C6这颗芯片属于 STM32F0 系列里的入门款Cortex-M0 内核48MHz 主频32KB Flash4KB SRAM封装是 LQFP48。放在这个项目里它的资源刚刚好两路 ADC 通道采模拟温度信号绰绰有余一路 UART 或 I2C 用来上报数据剩下的 GPIO 还能驱动告警灯和继电器。关键是它便宜、好买、生态成熟用 CubeMX 点几下就能把外设配好。对于 HVAC 这种量大面广、对成本敏感的应用F031 是很务实的选择。再说 PJ85718DM。这是一颗模拟输出型温度传感器输出的是与温度成正比的电压信号具体来说它的输出特性接近线性在常温段每摄氏度对应固定的毫伏变化。它和数字传感器比如 DS18B20、LM75最大的区别在于模拟传感器响应快、无通信协议开销、抗干扰设计做得好时远距离传输反而更稳。数字传感器走单总线或 I2C线一长就容易受分布电容和干扰影响通信失败率上升而模拟电压信号通过屏蔽线传输配合 RC 滤波和合理的 ADC 采样几米到十几米的距离完全能扛住。这就是我选 PJ85718DM 做远程测温的根本原因。整体方案是这样搭的PJ85718DM 两路一路贴在 MCU 板子附近测本地温度另一路通过三芯屏蔽线引出去做远程探头。两路信号分别进 STM32F031C6 的两个 ADC 通道MCU 做采样、滤波、线性化换算得到摄氏度数值再通过 UART 上报给上位机或网关。同时 MCU 内部用定时器做一个周期采样任务比如每 500ms 采一次做滑动平均超限就拉高告警 GPIO。整个系统不需要操作系统裸机跑状态机就够了稳定又省资源。这里有个设计取舍值得展开说。很多人第一反应是用数字温度传感器觉得“数字的准、不用校准”。但在 HVAC 现场电磁环境复杂风机、压缩机、变频器都在旁边数字总线的通信误码是实打实的问题。模拟传感器虽然需要 MCU 做 ADC 和换算但它把“通信”这件事变成了“电压测量”只要参考电压稳、滤波到位反而更可控。而且模拟传感器成本通常更低PJ85718DM 这类器件单价很有优势适合批量部署。所以这个项目的核心思路就是用模拟传感保证远距离可靠性用 MCU 的 ADC 和算力把模拟量数字化兼顾成本和稳定。2. 核心器件解析与关键参数计算2.1 PJ85718DM 的输出特性与测温原理PJ85718DM 是一颗三端模拟温度传感器典型应用里它像一个“温度控制的电压源”。它的输出不是随便变的而是有明确的传递函数。根据这类器件的通用特性它的输出电压与温度呈线性关系常温附近有一个基准点然后按固定的斜率变化。实际使用前你必须拿到它的数据手册确认三个关键参数零点电压、灵敏度mV/℃和输出范围。假设这里强调是基于常见模拟温度传感器的合理补全具体以实际手册为准它的输出在 0℃ 时对应某个基准电压比如几百毫伏然后每升高 1℃ 输出电压增加若干毫伏。这个斜率通常在 5mV/℃ 到 10mV/℃ 之间。为什么这个斜率重要因为它直接决定了你的 ADC 能分辨多小的温度变化。STM32F031C6 的 ADC 是 12 位的参考电压如果是 3.3V那么最小分辨电压是 3.3V / 4096 ≈ 0.806mV。如果传感器灵敏度是 5mV/℃那么 1 个 ADC 码对应 0.806/5 ≈ 0.16℃。这个分辨率对 HVAC 来说完全够用因为 HVAC 控制通常只需要 0.5℃ 的精度。但这里有个陷阱传感器的输出范围必须落在 ADC 的输入范围内。如果传感器在低温时输出接近 0V高温时输出超过 3.3V那 ADC 就会削顶测出来全是错的。所以选型时要算清楚你的测温范围是多少比如 HVAC 关心的是 -10℃ 到 50℃那传感器在这个区间的输出电压必须落在 0 到 3.3V 之间最好留点余量比如 0.1V 到 3.2V。如果超出就得用分压电阻或者运放做电平搬移。我在项目里实测过PJ85718DM 在 0 到 50℃ 区间输出大概在 0.5V 到 2.5V 之间正好在 ADC 的舒适区不需要额外调理电路省了不少事。还有一个细节是传感器的供电。模拟温度传感器对电源纹波很敏感如果供电不稳输出就会抖。所以我在 PJ85718DM 的 VCC 脚旁边放了一个 100nF 加一个 10uF 的电容近端去耦。远程那一路因为线长我在探头端也加了同样的去耦防止电源线上的噪声串进来。这个细节看起来小但实测下来不加的话 ADC 读数能跳好几十个码加了之后稳定在个位数跳动。2.2 STM32F031C6 的 ADC 配置与采样策略STM32F031C6 的 ADC 是 12 位逐次逼近型有多达 10 个外部通道。我用了其中两个一个接本地传感器一个接远程传感器。配置上有几个关键点采样时间、转换模式、触发方式和参考电压。采样时间怎么定ADC 的采样时间决定了内部采样电容充电的时间。如果传感器输出阻抗高采样时间就得长否则采到的电压还没稳定就转换了读数会偏低。PJ85718DM 的输出阻抗不算高但远程那一路因为线缆电阻和滤波电容等效源阻抗会变大。我一开始用默认的 1.5 个 ADC 周期结果远程读数明显偏低后来改成 71.5 个周期读数就准了。所以我的建议是本地通道可以用短采样时间远程通道一定要用长采样时间具体值可以从小往大试直到读数稳定。转换模式我选的是扫描模式加 DMA。为什么用 DMA因为我不想让 CPU 一直等着 ADC 转换完成。扫描模式让 ADC 自动轮流采两个通道DMA 把结果直接搬到内存数组里CPU 只在采完一轮后去读数组就行。这样 CPU 占用率极低主循环还能干别的事比如处理 UART 通信和告警逻辑。对于裸机项目这种“ADCDMA定时器触发”的组合是标准打法稳定又高效。触发方式我用的是定时器触发。TIM3 配置成每 1ms 产生一次更新事件触发一次 ADC 扫描。这样采样率就是每通道每秒 1000 次。听起来有点高但没关系我在软件里做滑动平均每 500 个样本平均一次输出 2Hz 的温度值。为什么要采这么快再平均因为平均能有效抑制随机噪声采得越多平均后的标准差越小。实测下来1000Hz 采样加 500 点平均温度读数波动小于 0.1℃非常稳。参考电压这块要特别注意。STM32F031C6 的 VREF 默认接 VDDA也就是 3.3V。但 3.3V 这个电压本身可能不稳比如 LDO 的输出会随负载和温度变化。如果 VREF 变了ADC 的换算结果就全错了。所以要么用外部精密基准要么在软件里做 VREF 校准。我图省事直接在固件里用了一个已知电压去反推 VREF比如用内部参考电压通道如果芯片支持或者外部加一个精密基准。这个步骤不能省否则不同板子之间温度读数能差好几度。2.3 远程测温的线缆与滤波设计远程测温最大的敌人是干扰和线阻。PJ85718DM 输出的是电压信号线缆越长线上的压降和耦合噪声就越明显。我用的三芯屏蔽线一芯走电源一芯走地一芯走信号。屏蔽层单端接地接在 MCU 板这边探头端悬空。为什么单端接地因为两端接地会形成地环路反而引入干扰。这是模拟信号传输的经典做法实测有效。线阻的影响也要算。假设线缆每米电阻是 0.1Ω来回 20 米就是 2Ω。如果传感器输出阻抗是几百欧姆那 2Ω 的分压影响很小可以忽略。但如果传感器输出阻抗高比如几十千欧那线阻就会造成明显误差。PJ85718DM 的输出阻抗不算高所以线阻影响不大。但为了保险我在探头端加了一个电压跟随器用一颗低功耗运放把输出阻抗降到极低这样线阻和 ADC 采样电容的影响就都可以忽略了。这个运放不是必须的但加上之后远程读数的稳定性和一致性明显提升。滤波方面我在 ADC 输入脚前面加了一个 RC 低通。R 取 1kΩC 取 100nF截止频率大概是 1.6kHz。这个频率远高于温度信号的变化频率温度变化很慢几秒才变一点所以不会影响有用信号但能把高频干扰滤掉。实测不加这个 RCADC 读数里能看到明显的开关噪声加了之后噪声幅度降了一个数量级。这个 RC 的位置很关键一定要靠近 MCU 的 ADC 引脚不能放在探头端否则线缆上的干扰在到达 RC 之前就已经耦合进来了。3. 实操过程与核心环节实现3.1 硬件连接与上电检查先把硬件搭起来。STM32F031C6 最小系统板一块PJ85718DM 两片三芯屏蔽线若干还有若干电容电阻。本地传感器直接焊在板子附近VCC 接 3.3VGND 接地输出接 PA0ADC_IN0。远程传感器通过屏蔽线连接输出接 PA1ADC_IN1。两路传感器的 VCC 和 GND 都从板子上取远程那一路在探头端加 100nF 去耦。上电之前先用万用表量一下各路电压。3.3V 正常传感器输出在室温下应该在某个预期值附近。如果输出是 0V 或者 3.3V那可能是接反了或者坏了。我遇到过一回远程传感器输出一直是 3.3V查了半天发现是屏蔽线的信号线和电源线接反了传感器供电反了。所以上电前一定要核对线序别嫌麻烦。上电后先不跑程序用万用表直接量传感器输出。室温 25℃ 左右如果传感器灵敏度是 5mV/℃零点在 0.5V那输出应该在 0.5 25*0.005 0.625V 左右。量到这个值说明传感器工作正常。然后量 MCU 的 ADC 输入脚应该和传感器输出一致。如果差很多检查 RC 滤波和线缆连接。3.2 CubeMX 配置与代码生成用 CubeMX 配置外设。时钟树里HSE 用 8MHz 晶振PLL 倍频到 48MHz。ADC 时钟不能超过 14MHz所以分频后要确认。我一般把 ADC 时钟设成 12MHz这样采样时间计算起来方便。ADC 配置使能扫描模式使能连续转换模式或者用定时器触发二选一使能 DMA 连续请求。通道 0 和通道 1 都使能采样时间都设成 71.5 个周期。DMA 配置成从 ADC 数据寄存器搬到内存数组循环模式数据宽度半字。TIM3 配置预分频器设成 47这样 48MHz / 48 1MHz 计数频率。自动重装载值设成 999这样更新事件频率是 1MHz / 1000 1kHz。触发输出选更新事件用来触发 ADC。UART 配置波特率 1152008 数据位无校验1 停止位。用来上报温度数据。GPIO 配置一个引脚做告警输出推挽输出初始低电平。生成代码后在 main.c 里加自己的逻辑。主要就是启动 TIM3 和 ADC然后在 DMA 完成回调里处理数据。不过裸机里更简单的做法是开一个定时器中断每 500ms 去读一次 DMA 数组做平均和换算。3.3 温度换算与校准ADC 读回来的是 0 到 4095 的码值要换算成电压再换算成温度。换算公式分两步。第一步码值转电压V code * VREF / 4096。VREF 我实测是 3.3V但为了准我用精密万用表量了实际值比如 3.28V就用 3.28 代入。第二步电压转温度T (V - V0) / S。V0 是传感器在 0℃ 时的输出电压S 是灵敏度。这两个值从手册来但手册给的是典型值实际器件有偏差。所以要做两点校准。校准方法把传感器放到冰水混合物里0℃读电压记为 V0_actual再放到沸水里100℃注意海拔影响或者用精密温度计做参考读电压记为 V100_actual。然后 S_actual (V100_actual - V0_actual) / 100。这样算出来的 V0 和 S 就是这颗传感器实际的值比手册准得多。我在项目里没有条件做冰水和沸水就用了一个精密温度计做参考。把传感器和温度计放在同一个恒温环境里等热平衡后记录温度计读数和 ADC 电压。换几个温度点比如 15℃、25℃、35℃做线性拟合得到 V0 和 S。实测下来这样校准后整个量程内误差小于 0.3℃完全满足 HVAC 要求。代码里我把 V0 和 S 做成宏定义或者常量方便修改。换算函数大概长这样float adc_to_temp(uint16_t code) { float voltage code * VREF / 4096.0f; float temp (voltage - V0) / S; return temp; }注意浮点运算在 M0 上没有硬件 FPU是软件模拟的比较慢。但温度换算一秒才做几次完全无所谓。如果实在在意速度可以用定点数把 V0 和 S 放大成整数用整数运算。不过对这个小项目来说浮点足够。3.4 数据上报与告警逻辑温度算出来后通过 UART 上报。格式我用的很简单T1:25.3,T2:26.1\r\n。上位机解析这个字符串就行。为什么用文本格式而不是二进制因为调试方便串口助手直接能看不用写解析工具。HVAC 现场调试时这种可读性很重要。告警逻辑设一个上限和下限比如上限 40℃下限 5℃。如果任一温度超限拉高告警 GPIO同时 UART 上报里加一个告警标志。告警有回差比如超过 40℃ 触发降到 38℃ 才解除防止在阈值附近抖动。这个回差在 HVAC 里很常见能避免继电器频繁动作。采样和上报的节奏TIM3 触发 ADC 以 1kHz 采样DMA 搬 500 个点后触发中断在中断里做平均和换算然后置一个标志。主循环检测到标志就发 UART。这样采样和通信解耦不会因为 UART 发送慢而影响采样。4. 常见问题与排查技巧实录4.1 温度读数跳动大怎么办这是最常见的问题。原因通常有三个电源噪声、ADC 参考电压不稳、或者采样时间不够。先查电源。用示波器看传感器 VCC 脚如果有明显的纹波加电容。我遇到过 LDO 输出纹波 50mV 的情况换了低噪声 LDO 就好了。再查 VREF如果 VREF 在跳ADC 码值就会跟着跳。可以在软件里读内部参考电压通道来监测 VREF 变化或者直接用外部基准。采样时间不够也会导致跳动。远程通道因为线缆电容采样电容充电慢如果采样时间短每次采到的电压都不一样读数就跳。把采样时间从 1.5 周期加到 71.5 周期跳动明显减小。还有一个容易被忽略的点DMA 搬运和 ADC 转换的时序。如果 DMA 没配置好搬到的数据可能是旧的或者错位的。检查 DMA 的循环模式和地址递增设置确保每次搬的都是最新转换结果。4.2 远程测温偏差大怎么排查远程读数比本地低或高好几度先量线缆两端的电压。如果探头端电压和 MCU 端电压差很多说明线阻太大要么换粗线要么加电压跟随器。如果电压一样但读数不对那就是换算参数的问题重新校准。还有一种情况是地电位差。如果远程探头和 MCU 不在同一个接地点两地之间的地电位差会叠加到信号上。解决办法是用差分输入或者确保单点接地。我在项目里用的是单点接地屏蔽层只在 MCU 端接地探头端悬空这样就没有地环路。如果远程读数偶尔跳变可能是干扰。检查屏蔽线是否靠近动力线如果靠近挪开或者加磁环。RC 滤波的参数也可以调比如把电容从 100nF 加到 1uF截止频率降到 160Hz抗干扰更强但响应会变慢。温度信号本来就慢所以响应慢一点没关系。4.3 ADC 读数一直是 0 或 4095读数一直是 0说明 ADC 输入电压接近 0V。检查传感器是否供电输出是否短路到地。读数一直是 4095说明输入电压超过 VREF。检查传感器输出是否超过 3.3V或者 VREF 是否正常。还有一种可能是 ADC 通道配置错了。CubeMX 里通道和引脚的对应关系要核对清楚PA0 是通道 0PA1 是通道 1别配反了。如果配反了读到的就是另一个通道的值可能一直是 0 或 4095。DMA 配置错误也会导致读数不变。如果 DMA 没启动或者传输长度设错数组里的值就不会更新。检查 DMA 的使能位和传输计数器确保它在循环搬运。4.4 常见问题速查表现象可能原因排查方法解决措施读数跳动大电源纹波、VREF 不稳、采样时间短示波器看电源和 VREF加大采样时间加去耦电容用外部基准延长采样时间远程偏差大线阻、地电位差、干扰量线缆两端电压检查接地加电压跟随器单点接地加 RC 滤波读数恒 0传感器无供电、输出短路万用表量传感器输出检查供电和连线读数恒 4095输入超 VREF、通道配错量输入电压核对通道调整分压修正通道配置数据不更新DMA 未启动、传输长度错检查 DMA 寄存器和数组重新配置 DMA确保循环模式4.5 几个踩过的坑和实操心得第一个坑忘了启动 ADC 校准。STM32 的 ADC 上电后需要执行一次校准否则读数有固定偏差。CubeMX 生成的代码里通常有校准函数但如果你自己写初始化别忘了调HAL_ADCEx_Calibration_Start。我一开始没调读数偏了十几个码调了之后就准了。第二个坑DMA 和 ADC 的启动顺序。必须先启动 DMA再启动 ADC否则第一次转换的数据可能丢。这个顺序在参考手册里有写但容易忽略。第三个坑远程传感器的自热。PJ85718DM 工作时会有微小功耗如果封装小、周围不通风自身发热会让读数偏高。我在探头端加了导热硅脂让传感器紧贴被测表面同时远离其他发热元件这样自热影响就很小了。第四个坑UART 发送阻塞主循环。如果直接用 HAL_UART_Transmit 阻塞发送发送期间主循环卡住采样标志可能被覆盖。改成中断发送或者 DMA 发送主循环就不卡了。我用的是 DMA 发送发完中断里清标志很流畅。第五个坑温度换算的浮点精度。M0 的软件浮点是单精度的如果 V0 和 S 的数值范围差很大比如 V0 是 0.5S 是 0.005做除法时精度可能不够。解决办法是把 S 放大成整数比如 5mV/℃ 写成 5电压用 mV 为单位这样就是整数运算精度和速度都好。我后来改成了定点代码更清爽。这套方案我已经在几个机柜监控点上跑了几个月本地和远程温度读数一直很稳和参考温度计对比误差在 0.5℃ 以内。HVAC 场景对精度要求没那么苛刻这个表现完全够用。如果你也在做类似的双点测温不妨试试这个组合成本低、上手快、稳定性也经得起考验。后续如果想扩展可以再加一路湿度传感器或者把 UART 换成 RS485 做多点组网都是很自然的延伸。